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())
相关推荐
IT_陈寒10 分钟前
Redis的SETNX并发问题让我加了三天班
前端·人工智能·后端
demo007x25 分钟前
Docling 文档转换以及技术架构分析
前端·后端·程序员
京东云开发者1 小时前
京东市民服务又“上新”!这次是黑龙江“龙易办”
前端
袋鱼不重2 小时前
我的神奇同事,AI 用多了居然写了个 Open In Codex
前端·后端·ai编程
用户8356290780512 小时前
使用 Python 操作 Word 内容控件
后端·python
像我这样帅的人丶你还2 小时前
啥? 前端也要会干Java?🛵🛵🛵
后端
竹林8182 小时前
Web3表单签名验证:我用 wagmi 和 ethers 给 DApp 加了一个“免密登录”,踩坑记录全在这了
javascript
Hommy882 小时前
【剪映小助手】添加贴纸接口(Add Sticker)
后端·github·剪映小助手·视频剪辑自动化·剪映api
用户6990304848752 小时前
try catch使用场景 处理同步代码错误兼容用的
javascript·uni-app
雪碧聊技术2 小时前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript