添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

前言

众所周知,mongoose的日期格式是ISODate,也就是使用的utc时间,举个栗子: 2020-12-11T16:00:00.000Z , T 表示分隔符, Z 表示的是UTC。

UTC:世界标准时间,在标准时间上加上8小时,即东八区时间,也就是北京时间。

咱举个例子:

北京时间: 2020-12-12 00:00:00 对应的国际标准时间格式为: 2020-12-11T16:00:00.000Z

当我们的前端页面通过接口拿到我的utc时间后,一般通过new Date(时间),就能快速的转换成当地的时间。

这些周知的我就不再多举例了。

笔记原因

做这个笔记前,我遇到了时间进入到数据库没有准确的转换为utc,于是,好奇心驱使,我们开启mongoose的debug模式,来看看是什么实际mongoose到原生层的实际过程。

1
2
// 开启mongoose调试
this.app.mongoose.set('debug', true)

举例,我有一个schema,里面有个updateDate,我们先来看看不同的日期插入数据库时候,实际的表现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module.exports = (app) => {
const mongoose = app.mongoose
const Schema = mongoose.Schema

const FileSchema = new Schema(
{
fileName: { type: String }, // 文件名
uploadDate: { type: Date }, // 上传创建日期
creatorName: { type: String }, // 创建者姓名
},
{
collection: 'sys_files',
}
)

return mongoose.model('File', FileSchema)
}
  • 方式一:使用new Date 插入
    1
    2
    3
    4
    5
    const deliver = await ctx.model.Delivery.File.create({
    fileName: '文件名',
    uploadDate: new Date("2021-12-12 00:00:00"),
    creatorName: "张三",
    })
  • 通过debug日志:

    1
    Mongoose: sys_files.insertOne({ isDel: false, _id: ObjectId("61b5599cba1fcfeeb79c57cd"), fileName: '文件名', uploadDate: new Date("Sat, 11 Dec 2021 16:00:00 GMT"), creatorName: '张三', __v: 0}, { session: null })

    结论: `

    我们发现mongoose的ORM层的 create 实际调用了 insertOne ,插入的本地时间 new Date("2021-12-12 00:00:00") 2021-12-11T16:00:00.000Z )到达原生层变成了 Sat, 11 Dec 2021 16:00:00 GMT 并在进行了一次new Date(),

    所以整个orm层到mongodb原生层的过程是这样的:
    日期传入 -> (ORM)转换为GMT零时区 -> (ORM)new Date()转为ISODate -> 入库

  • -> new Date("2021-12-12 00:00:00") 传入 -> 2021-12-11T16:00:00.000Z
  • ->(ORM)转换为GMT零时区 Sat, 11 Dec 2021 16:00:00 GMT
  • ->(ORM)new Date()转为ISODate new Date("Sat, 11 Dec 2021 16:00:00 GMT") -> 2020-12-11T16:00:00.000Z
  • 我们在拿一个字符串时间和moment时间对象来校验是不是这个过程: 日期传入 -> (ORM)转换为GMT零时区 -> (ORM)new Date()转为ISODate -> 入库

  • 方式二:使用String 字符串插入
    1
    2
    3
    4
    5
    6
    7

    const deliver = await ctx.model.Delivery.File.create({
    fileName: '文件名',
    uploadDate: "2021-12-12 00:00:00",
    creatorName: "李四",
    })

  • -> 2021-12-12 00:00:00 传入

  • ->(ORM)转换为GMT零时区 Sat, 11 Dec 2021 16:00:00 GMT

  • ->(ORM)new Date()转为ISODate new Date("Sat, 11 Dec 2021 16:00:00 GMT") -> 2020-12-11T16:00:00.000Z

  • -> 入库

  • 方式三:使用moment 插入

    1
    2
    3
    4
    5
    6

    const deliver = await ctx.model.Delivery.File.create({
    fileName: '文件名',
    uploadDate: moment("2021-12-12 00:00:00"),
    creatorName: '王五',
    })
  • -> moment("2021-12-12 00:00:00") 传入 -> Moment<2021-12-12T00:00:00+08:00>
  • ->(ORM)转换为GMT零时区 Sat, 11 Dec 2021 16:00:00 GMT
  • ->(ORM)new Date()转为ISODate new Date("Sat, 11 Dec 2021 16:00:00 GMT") -> 2020-12-11T16:00:00.000Z
  • others

    我们发现当我们的时间只要是精确到时分秒,进入到mongodb数据库后,都能正确的转换成UTC时间。

    那我们来试试 年月日的情况

    1
    2
    3
    4
    5
    const file = await ctx.model.Delivery.File.create({
    fileName: '文件名',
    uploadDate: new Date('2021-12-12'),
    creatorName: '刘九',
    })

    结论: `

  • -> new Date('2021-12-12') 传入 -> 2021-12-12T00:00:00.000Z 注意此处年月日时间转换为UTC时间与上面带时分秒的差异
  • ->(ORM)转换为GMT零时区 Sat, 11 Dec 2021 00:00:00 GMT
  • ->(ORM)new Date()转为ISODate new Date("Sat, 11 Dec 2021 00:00:00 GMT") -> 2020-12-12T00:00:00.000Z
  • 这也就解释了为什么本人在项目中传入 2021-12-12 的日期最终却变成了utc 2020-12-12T00:00:00.000Z ,也就是为什么new Date()本地时间会多出来8个小时的原因了。

    mongoose这个ORM实际做了一步强制new Date()转换为utc时间。所以无论传入什么本地时间,都会强制转换mongodb所需要的ISODate时期格式。
    所以无论是moment、dayjs等时间库的时间,最后都会被momgoose强制转换为new Date 的UTC时间。与用什么时间库或时间格式并无直接关系。

    番外篇

    我们来验证下查询的时候,传入的时间是不是也会通过mongoose自动强制new Date
    De6b3B
    uuLCtR

    验证发现流程:

  • -> 传入时间
  • ->(ORM)转换为GMT零时区 Sat, 11 Dec 2021 00:00:00 GMT
  • ->(ORM)new Date()转为ISODate new Date("Sat, 11 Dec 2021 00:00:00 GMT") -> 2020-12-12T00:00:00.000Z
  •