JS中所有与Date日期相关的问题,看这一篇文章就够了!超级详细,学不会找我

最近本人在全栈开发的过程中,需要将日期存入数据库。而这篇文章就是作者不断踩坑后的产出,希望可以帮助到大家。

在大家阅读之前,可以先思考一个问题: 我想将用户输入的日期,通过后端接口,写入数据库中。大家会怎么做?

作者总结出了两种方法,同时介绍了各自的优缺点。科普了在工作中可能会用到的日期小知识,现在大家继续看下去吧!

JS的日期数据类型

在JS中,处理日期和时间主要是通过Date对象。接下来我将手把手教你如何创建一个Date实例,同时告诉你各个部分的含义。准备好了吗?我们开始了

创建Date实例

在JS中,通过new关键字和Date()构造函数来创建Date实例:

js 复制代码
let now = new Date()
console.log(now)

现在我们创建了一个Date实例,如果在Node.js中输出它的话,会得到什么结果呢?

我们发现,console.log()输出Date实例,会输出一串字符串。那么这段字符串是什么意思呢?我们现在来看看:

  • 2024-04-10:日期部分,遵循YYYY-MM-DD 的格式
  • T:分割符,主要的作用就是分割日期和时间,让计算机和用户知道,接下来要显示时间了
  • 06:08:01.522:时间部分,遵循HH:MM:SS.mmm 其中的mmm为毫秒部分
  • Z:标识符,用于标明时区,标识符为Z,说明这个时间是按照UTC时区表示的。
    • UTC时区,即 协调世界时时区(Coordinated Universal Time),是世界时间标准的基础。UTC不属于任何特定的地理时区,而是通过原子时钟精确计时,通过科学方法确定的。无论身处世界的哪一个时区,UTC时间都是一致的
    • Z实际上指的是Zulu时间,即另一种说法的UTC。标识为Z说明这个时间是相对于UTC的,没有时区偏差。 我猜你现在有点云里雾里了😵,日期部分、T分隔符和时间部分还能理解,这个时区又是个啥?为啥UTC时区要用Z表示?不要担心,现在我们开始说人话:

时区

高中地理说过,整个地球被分为了24个时区,如果你坐飞机一路向东,每经过一个时区,你的手表上的时间都应该修改一小时。

假设我们在中国是12号的12点,要吃午饭了🍚。而按照时区的划分,美国中部现在却是11号的19点,还是晚上。 如果按照当地时间的话,地球上不同时区的时间都是不同的 这个问题可就太头疼了,假如我要做外商,需要做一个限时抢购功能。我如果使用的是中国时区,从10号14:00点开抢,那么美国的用户应该在几点开抢呢?想想就头痛。

为了解决时区不同,时间不同的问题,科学家们引入了UTC时区,即协调世界时(Coordinated Universal Time)

UTC时区

UTC时区消除了世界各地的时间差异,不管你身处地球何处,你的UTC时区的时间与其他任何地方的时间都是一样的。

为什么呢?因为UTC是建立在原子时间的基础上,感兴趣的小伙伴可以自行了解

为什么UTC时区要用Z来标识呢?

这其实就涉及到历史背景了,在过去,使用 NATO(北大西洋公约组织)音标字母(也称为国际音标字母)来代表不同的时区。例如,"Alpha"代表 UTC+1,"Bravo" 代表 UTC+2,以此类推。在这个系统中,"Zulu" 代表了 0 时区,即 UTC。

总是用大写字母Z来标识UTC时区,其实是一个历史遗留叫法,就好比JavaScript里面有个Java,你能说JavaScript和Java有关系吗?

浏览器输出Date实例

上文中为了介绍JS日期的字符串表达方式,我们使用的是Node.js环境,输出的是一行字符串。而我们知道Date实例实际上是一个对象,通过log输出得到的字符串日期其实是Date实例序列化之后的结果。

那么我们如果在浏览器环境输出Date实例,会发生什么呢?

js 复制代码
let browserNow = new Date()
console.log(browserNow)

欸!神奇的事情发生了,为什么在Node环境下和浏览器环境下输出的结果不一样呢?

别慌别急!带好墨镜🕶,跟着老司机,我们继续深入了解

让我们先了解输出的这段字符串是什么意思:

  • Web:表示今天是星期三
  • Apr:表示现在是四月份April
  • 10:表示现在是十号
  • 2024:表示今年是2024年
  • 14:31:23:表示现在是下午14点32分23秒
  • GMT+0800:是一个时区标志
    • GMT:格林尼治标准时间
    • +0800:表示相对于格林尼治标准时间的偏移量,偏移量为+0800。中国的时区统一使用东八区,这整个GMT+0800的意思是,当前所在时区比GMT时区要快8小时
  • (中国标准时间):提供了时区具体名称,中国整体使用东八区时间

为什么Node.js环境与浏览器环境Date实例输出不同

首先我们要知道,Date实例是对象。如果直接输出的话,应当输出一个对象才对。但是我们通过console.log()输出的都是字符串,这时为什么呢?

console.log()输出的Date类型与环境有关。在浏览器中,会默认先调用Date.prototyoe.toString()方法,转化为我们在浏览器中看到的格式

为了验证我们的说法,我们在Node.js环境下,手动调用Date.prototype.toString()方法再输出

js 复制代码
let now = new Date()
console.log(now.toString())

这时候我们发现,Node.js环境下的输出与浏览器一致了!

那么在Node.js中,是不是调用Date.prototpye.toUTCString()的方法,转化为UTC格式的字符串输出呢? 同样的,为了验证我们的说法,我们在浏览器环境下,手动调用Date.prototype.toUTCString()

js 复制代码
let now = new Date()
console.log(now.toUTCString())

我们发现,欸?!怎么回事,为什么不是2024-04-10T07:28:03.611Z的格式?别急!让我细细道来 首先同样是输出当前日期,将为什么调用Date实例的toUTCString()方法后,输出的时间是4月10号的早上7:26;而调用Date实例的toString()方法,输出的时间是4月10号的下午15:11呢?

Date实例的三种格式转化方法

在JS中,Date实例有三种格式转换的方法,它们分别为:

  • toString():将Date对象转化为字符串,同时使用浏览器所在本地时区的时间表示。在中国的话会显示中国时区的时间,美国的话会显示美国时区的时间

  • toUTCString():将Date对象转化为符合RFC 1123规范的字符串,统一按照UTC时区显示时间。所以与中国时区的时间不同。其中的GMT是格林威治标准时间,GTM是基于地球自转和太阳相对于格林威治天文台的位置来计算的时间。在1972年以前,它曾经作为全球时间标准

为什么调用toUTCSting(),最后的时区标识是GMT?这其实又是一个JS的历史遗留问题,因为GMT术语用的更多,这是一个历史习惯问题。实际上的时间,还是基于UTC时区的。JS真的好多历史遗留问题......

  • toISOString():将Date对象转化为符合ISO 8601规范的字符串,同时这个字符串是基于UTC时区的。而这个格式就是之前在node.js环境下输出的日期字符串格式
js 复制代码
let now = new Date()
console.log(now.toISOStirng())

node.js环境:

浏览器环境:

获取时间戳

在JS中,我们可以通过调用Date实例的.getTime()方法,将当前Date实例转化为对应的时间戳

js 复制代码
let now = new Date()
console.log(now.getTime())

那么什么是时间戳呢?在JS里时间戳表示的是从UTC时区的1970年1月1日到现在所经过的毫秒数。注意是毫秒数哦!这点很重要。 时间戳1712735944258的意思是,按照UTC时区的1970年1月1日后,经过1712735944258毫秒

我们也可以通过Date.now()的方法,直接获取当前时间戳

js 复制代码
let now = Date.now()
console.log(now)

要注意的是,时间戳是number数字类型,不是对象也不是字符串,注意是number类型!

JS的Date日期类型总结

我们可以通过new关键字+Date构造函数创建Date实例,该Date实例默认储存当前时间。 Date实例的字符串输出有三种格式:

  • toString():转化为符合当地规范的字符串,不同地区规范不同,时区为浏览器本地时区,不同地区时间不同
  • toUTCString():转化为符合RFC 1123规范的字符串,时区为UTC时区,不同地区时间相同
  • toISOString():转化为符合ISO 8601规范的字符串,时区为UTC时区,不同地区时间相同

RFC 1123规范的时间字符串

  • Web:表示今天是星期三
  • 10:表示现在是十号
  • Apr:表示现在是四月份April
  • 2024:表示今年是2024年
  • 07:38:16:表示现在是下午14点32分23秒
  • GMT:是一个时区标志
    • GMT:格林尼治标准时间
    • 由于JS历史遗留原因,虽然标识是GMT,但实际的时间还是按照UTC时区标准的

ISO 8601规范的时间字符串

  • 2024-04-10:日期部分,遵循YYYY-MM-DD 的格式
  • T:分割符,主要的作用就是分割日期和时间,让计算机和用户知道,接下来要显示时间了
  • 07:47:28.199:时间部分,遵循HH:MM:SS.mmm 其中的mmm为毫秒部分
  • Z:标识符,用于标明时区,标识符为Z,说明这个时间是按照UTC时区表示的。
    • UTC时区,即 协调世界时时区(Coordinated Universal Time),不同地区时间相同
    • Z实际上指的是Zulu时间,即另一种说法的UTC。(又是一个历史遗留问题......)

Mysql的日期数据类型

现在我们认识了JS中的Date日期类型,但是这还不够,因为我们的目标是星辰大海⛵! 为了成为全栈工程师,我们也需要了解Mysql的日期数据类型,这样在全栈项目中,需要存入日期数据时,我们就能得心应手,老板看我们这么厉害,工资💴也水涨船高

话不多说,我们现在来看看Mysql中的日期数据类型

在Mysql中有五种常用的日期数据类型:

  • DATE:用于存储日期,字符串格式为YYYY-MM-DD,范围从1000-01-019999-12-31
sql 复制代码
INSERT
    `time` (date)
VALUES (
        '2024-4-10'
    )
  • TIME:用于存储时间值,字符串格式为HH:MM:SS,范围为从-838:59:59838:59:59 。在Mysql5.6.4版本后支持微秒部分,即HH:MM:SS.mmm
mysql 复制代码
INSERT
    `time` (time, datetime)
VALUES (
        '16:05:30.222'
    )
  • DATETIME:用于存储日期和时间,字符串格式为YYYY-MM-DD HH:MM:SS 。在Mysql5.6.4版本后支持微秒部分
mysql 复制代码
INSERT
    `time` (datetime)
VALUES (
        '2024-04-10 16:05:30.222'
    )

TIMESTAMP Mysql的时间戳

为什么要将Mysql里面的timestamp单独讲呢?因为这一段跟JS中的时间戳有着很大的区别,如果没有仔细区分的话,新手非常容易踩坑(没错,说的就是我/(ㄒoㄒ)/)

我们之前说过,在JS中,时间戳是从1970年1月1日到现在所经过的毫秒数,是number类型的数据 但是在mysql中,时间戳是从1970年1月1日到现在所经过的秒数,注意是秒,不是毫秒 但是在储存的时候,却与datetime相似,储存的是YYYY-MM-DD HH:MM:SS格式的字符串

简单来说,JS的时间戳是按毫秒计时的数字; 而Mysql的时间戳却是按秒计数的数字,存储的却是字符串

我知道你很奇怪,也很迷茫,但你先别迷茫🙅‍,看完这几个例子就懂了

如果直接将JS的时间戳写入Mysql中,是肯定会报错的,例如:

sql 复制代码
INSERT
    `time` (timestamp)
VALUES (
        1712735944258
    )

首先JS的时间戳以毫秒为单位,而mysql时间戳以秒为单位,单位不同肯定存不进去。 将1712735944258除以1000后取整数,得到1712735944,这样就将毫秒为单位的时间戳,转化为了以秒为单位的时间戳。现在我们是不是就可以存入mysql了呢?我们试试:

sql 复制代码
INSERT
    `time` (timestamp)
VALUES (
        1712735944
    )

还是报错了!这时候不要气馁,我们离正确答案以及很近了。

我们报错的原因在于,mysql的timestamp类型的日期数据,存储的时候还是按照YYYY-MM-DD HH:MM:SS格式的字符串存储的,所以正确的写法是,写入YYYY-MM-DD HH:MM:SS的时间字符串

mysql 复制代码
INSERT
    `time` (timestamp)
VALUES (
        '2024-4-10 20:18:30'
    )

mysql的TIMESTAMP类型到底是这么个事?

看到这里,不知道你有没有这样的疑问:TIMESTAMP类型和DATETIME类型有什么区别?为什么说Mysql的时间戳是以秒为单位的,但却不能直接写入TIMESTAMP类型的日期中?

好的,我这就来解答您的疑问。但请放轻松,饭要一口一口吃,学习我们也要一步一步的来

TIMESTAMP类型和DATETIME类型有什么区别

从数据写入的角度来看,没有任何区别。写入DATETIME类型和写入TIMESTAMP类型的mysql语法都是一样的

mysql 复制代码
INSERT
    `time` (datetime, timestamp)
VALUES (
        '2024-04-10 16:05:30.222', '2024-04-10 16:05:30.222'
    )

但是这两者在使用方面,确实存在区别,这两者最大的区别在于时区处理

  • DATETIME不存储任何与时区相关的信息,存进去是多少,取出来就是多少
  • TIMESTAMP存储时,会将时间字符串自动转化为UTC时区,取出来时会转化为服务器的本地时区,例如中国的东八区。因此TIMESTAMP适合存储跨时区的日期和时间,如果你的用户面向全球,你最好用TIMESTAMP类型存储日期。

为什么说Mysql的时间戳是以秒为单位的,但以秒为单位的时间戳却不能直接写入TIMESTAMP类型的日期中?

mysql的TIMESTAMP类型背后的概念和存储机制确实是以秒为单位的,但是在存入数据的时候,mysql要求为YYYY-MM-DD HH:MM:SS格式的字符串。

虽然我们不能直接讲JS的毫秒时间戳 直接存入mysql,但是借助mysql的FROM_UNIXTIME()函数,我们可以间接做到:

sql 复制代码
INSERT
    `time` (timestamp)
VALUES (
        FROM_UNIXTIME(1712735944258/1000)
    )

在上面的代码中,我们先将JS的以毫秒为单位的时间戳 除以 1000,转化以秒为单位的时间戳。 然后将以秒为单位的时间戳,通过FROM_UNIXTIME()函数转化为了YYYY-MM-DD HH:MM:SS格式的字符串

将JS的Date类型写入Mysql的两种方法

根据上文的学习,现在我们来到实战环节。总的来说我们有两种方法将JS的Date类型写入mysql:

  • post传递日期字符串
  • post传递时间戳

日期字符串

首先JS中,最接近Mysql的日期格式YYYY-MM-DD HH:MM:SS的,就是ISO 8601规范的时间字符串YYYY-MM-DDTHH:MM:SS.mmm

在mysql5.6.8版本后,你可以写入毫秒。但是在这个版本之前,写入会报错。请读者分辨自己的mysql版本

所以我们在post传递给后端接口的时候,可以先调用Date实例的.toISOString()方法,然后将返回的YYYY-MM-DDTHH:MM:SS.mmmZ格式的字符串进一步处理就好了

我说的进一步处理,指的是:

  • 将分隔符T用空格代替
  • 去掉末尾的时区标识符Z 最终转化为YYYY-MM-DD HH:MM:SS.mmm的格式,就可以直接写入mysql数据库啦
js 复制代码
let now = new Date()
let tempStr = now.toISOString()
let prasedDate = tempStr.replace("T", " ").replace("Z", "")
console.log(prasedDate)

然后将这个字符串通过post传递参数,后端直接写入数据库就可以了,具体的实现方法就不讲了,感兴趣的同学可以去学express框架或者nest框架

sql 复制代码
INSERT
    `time` (timestamp)
VALUES (
        '2024-04-10 13:49:01.796'
    )

时间戳转换

另一种方法就是前面介绍的,将JS的以毫秒为单位的时间戳转化为以秒为单位的时间戳,然后作为参数传递给后端。后端再通过mysql的FROM_UNIXTIME()函数解析成对应的日期字符串格式

js 复制代码
let now = new Date()
let timeStampBySeconds = Math.floor(now.getTime()/1000)
console.log(timeStampBySeconds)

后端接收到后,调用FROM_UNIXTIME()函数

sql 复制代码
INSERT
    `time` (timestamp)
VALUES (
        FROM_UNIXTIME(1712757304) 
    )

到这里,我们的教程就写完了,最后再来一个彩蛋,附带上我最常用的JS的Date实例操作

JS常见的Date日期操作

创建特定的日期

通过时间字符串创建

通过Date()构造函数,根据上文的格式,我们可以自己写出特定的时间

js 复制代码
let now = new Date("2024-04-09T15:26:00")
console.log(now)
//2024-04-09T07:26:00.000Z

通过年、月、日等参数

我们可以通过向Date()构造函数依次传入年、月、日,可选传入时、分、秒、毫秒

必须按照顺序依次输入,不能省略年份,只传入月份和日

  • year
  • month:注意!月份从0开始!0表示1月
  • day
  • ?hour
  • ?minute
  • ?second
  • ?millisecond
js 复制代码
let today = new Date(2024, 3, 9)
console.log(today)
//2024-04-08T16:00:00.000Z

let now = new Date(2024, 3, 9, 15, 34, 20, 111)
console.log(now)
//2024-04-09T07:34:20.111Z

获取特定年份、月份、日等

比如说,我想获取当前的年份,我可以先创建一个Date对象,在这个Date对象中包含年份、月份、日等 然后通过方法去获取年份、月份、日等

  • .getFullYear()
  • .getMonth() + 1:获取月份,月份从0开始,1月为0,12月为11
  • .getDate():获取一个月中的第几天,1号为1,31号为31
  • .getDay():获取一周中的第几天,周日为0,周六为6
  • .getHours()
  • .getMinutes()
  • .getSeconds()
  • .getMilliseconds() 这些方法都是根据本地时间计算的,如果想获取UTC时区,可以使用UTC版本,如
  • .getUTCFullYear()
  • .getUTCMonth()
  • 以此类推

时间戳

可以使用Date实例的getTime()方法将日期和时间转化为时间戳。时间戳表示的是从UTC时间的1970年1月1日到现在所经过的毫秒数。

js 复制代码
let now = new Date()
let timestamp = now.getTime()
console.log(timestamp)

获取当前时间戳

通过Date.now()方法,返回当前时间戳

js 复制代码
let currentTimestamp = Date.now()
console.log(currentTimestamp)

将时间戳转化为Date对象

只需将时间戳作为参数,传入Date()构造函数,就会返回对应的Date实例

js 复制代码
let timestamp = 1704067200000
let date = new Date(timestamp)
console.log(date.toString())
相关推荐
石小石Orz5 分钟前
Three.js + AI:AI 算法生成 3D 萤火虫飞舞效果~
javascript·人工智能·算法
小行星1257 分钟前
前端预览pdf文件流
前端·javascript·vue.js
join88 分钟前
解决vue-pdf的签章不显示问题
javascript·vue.js·pdf
2301_8112743110 分钟前
大数据基于Spring Boot的化妆品推荐系统的设计与实现
大数据·spring boot·后端
小行星12514 分钟前
前端把dom页面转为pdf文件下载和弹窗预览
前端·javascript·vue.js·pdf
Lysun00123 分钟前
[less] Operation on an invalid type
前端·vue·less·sass·scss
土豆湿30 分钟前
拥抱极简主义前端开发:NoCss.js 引领无 CSS 编程潮流
开发语言·javascript·css
J总裁的小芒果39 分钟前
Vue3 el-table 默认选中 传入的数组
前端·javascript·elementui·typescript
Lei_zhen9641 分钟前
记录一次electron-builder报错ENOENT: no such file or directory, rename xxxx的问题
前端·javascript·electron
辣条小哥哥43 分钟前
electron主进程和渲染进程之间的通信
javascript·electron·ecmascript