前言
有些东西看起来不起眼,但是到了真正的开发中,会给你使很大的绊子。比如说在js中对于时间的处理,不是什么大问题,但是每次遇到都会在这上面花费一定的时间,所以我打算趁着周末整理一下js中有关时间和日期方面的知识。
一、一些概念
1. 时区
我们的世界有数百个时区。 在JavaScript中,我们只关心两个, 本地时间和协调世界时(UTC)。
- 本地时间是指你的计算机所在的时区。
- UTC实际上是格林威治标准时间(GMT)的同义词
默认情况下,JS中的几乎每个日期方法(除了一个)都是本地时间。 只有指定UTC,才能获得 UTC 时间 。
2. Date对象
ECMAScript的Date类型是一个引用类型,引用类型是把数据和功能组织到一起的结构,这听起来好像就是类,但是不是。
js虽然是一门面向对象的语言,但是ECMAScript缺少传统的面向对象编程语言所具备的某些基本结构,包括类和接口。
引用类型有时候也被称为对象定义,因为他们描述了自己的对象应有的属性和方法。
Date类型将日期保存为自协调世界时(UTC)时间1970年1月1日午夜(零时)至今所经过的毫秒数。
要创建日期对象,就是用new操作符来调用Date()构造函数:
let now = new Date()
二、创建日期
在不给Date构造函数传参数的情况下,创建的对象将保存当前日期和时间。
const date = new Date()
console.log(date) // Sun Sep 12 2021 10:14:58 GMT+0800 (中国标准时间)
要想基于其他日期和时间创建日期对象,必须传入其毫秒表示(UNIX纪元1970年1月1日午夜之后的毫秒数)。
传入的参数通常有3种常用的方式:
- 使用日期字符串参数
- 使用一系列的参数
- 时间戳参数
1. 使用日期字符串参数:
- 日期字符串的格式必须是 *年-月-日*,还要注意,必须是字符串哈;
- 如果格式不是 *年-月-日*,会报出错误的时间信息或直接报错,因为你不能确定我指的是哪一个,除非你知道我正在使用的日期系统。
- 如果不是字符串,也会出问题,可能会直接返回1970年1月1日午夜时间
const date2 = new Date('2021-09-12')
console.log(date2) // Sun Sep 12 2021 08:00:00 GMT+0800 (中国标准时间) 正确表达√
const date3 = new Date(2021-09-12)
console.log(date3) // Thu Jan 01 1970 08:00:02 GMT+0800 (中国标准时间) 错了
const date4 = new Date('12-09-2021')
console.log(date4) // Thu Dec 09 2021 00:00:00 GMT+0800 (中国标准时间) 错了
在js中,如果要使用日期字符串参数,则需要使用全球都能接受的格式,其中一种格式是ISO8601扩展格式
// ISO 8601 Extended format
`YYYY-MM-DDTHH:mm:ss:sssZ`
- YYYY:4位数年份
- MM:两位数月份(即 1月为01,12月为12)
- DD:两位数的日期(0到31)
- -:日期分隔符
- T:表示开始时间
- HH:24位小时数(0到23)
- mm:分钟(0到59)
- ss:秒(0到59)
- sss:毫秒(0到999)
- ::时间分隔符
- Z:如果存在 Z,则日期将设置为UTC,如果 Z不存在,则为本地时间。
其中小时,分钟,秒和毫秒是可选的,就像上面的date2一样。
但是,如果你只制定了日期,没有指定T后面的时间,则会获得UTC格式设置的日期
如果要使用日期字符串参数方法在“本地时间”中创建日期,则需要包括时间。如果包含时间,则需要至少写入 HH和 mm
// 格林尼治9月12日零点的时间,在北京时间是上午八点了
console.log(date2) // Sun Sep 12 2021 08:00:00 GMT+0800 (中国标准时间)
// 但是给出时间之后,就会老老实实的显示出本地的这个时间
const date5 = new Date('2021-09-12T00:00')
console.log(date5) // Sun Sep 12 2021 00:00:00 GMT+0800 (中国标准时间)
总结:使用日期字符串参数的创建的本地时间与UTC的比较可能是一个难以捕捉的错误。所以,建议不要使用日期字符串创建日期方式。
那不建议我们用这种方式,用什么方式呢?
2. 使用一系列的参数:
最多可以传入七个参数来创建日期/时间
-
Year:4位数年份
-
Month:一年中的某月(0-11)
-
Day:每月的某天(1-31),如果省略,则默认为1
-
Hour:一天中的小时(0-23)
-
Minutes:分钟(0-59),如果省略,则默认为0
-
Seconds:秒(0-59),如果省略,则默认为0
-
Milliseconds:毫秒(0-999),如果省略,则默认为0
许多开发人员比较少用这种方式,因为它看起来很复杂,但它实际上非常简单。可以从左到右记忆:年、月、日、小时、分钟、秒和毫秒。一个很需要注意的点:Month是从 0开始的!
举几个例子:
// 21st March 1988, 12am, Local Time.
new Date(1988, 2, 21)
// 25th December 2019, 8am, Local Time.
new Date(2019, 11, 25, 8)
// 6th November 2023, 2:20am, Local Time
new Date(2023, 10, 6, 2, 20)
// 11th June 2019, 5:23:59am, Local Time
new Date(2019, 5, 11, 5, 23, 59)
注意,使用参数创建的日期都是本地时间
使用参数的还有一个好处是不会在本地时间和UTC之间混淆,如果需要UTC时间,请以这种方式创建UTC 日期:
// 11th June 2019, 12am, UTC.
new Date(Date.UTC(2019, 5, 11))
3.使用时间戳来创建日期:
在JS中,时间戳是自1970年1月1日以来经过的毫秒数(1970年1月1日也称为Unix纪元时间)。根据大牛们的经验,很少使用时间戳来创建日期,一般使用时间戳来比较不同的日期或者格式化日期,后面再讨论!
三、格式化日期
1.先diss一下js
多数编程语言都提供了一种格式工具来创您想要的任何日期格式 例如,在PHP中,可以将 date(“d M Y”)格式化成 231月2019这样的日期。
但是!在js中格式化日期并不容易。
原生Date对象提供了七种格式化方法,这七种方法中的每一种都会给你一个特定的价值,而且他们毫无用处。
const date = new Date(2019, 0, 23, 17, 23, 42)
- toString:格式化成 “Wed Jan 23 2019 17:23:42 GMT+0800 (中国标准时间)”
- toDateString: 格式化成 “Wed Jan 23 2019”
- toLocaleString:格式化成 “2019/1/23 下午5:23:42”
- toLocaleDateString:格式化成 “2019/1/23”
- toGMTString:格式化成 “Wed, 23 Jan 2019 09:23:42 GMT”
- toUTCString:格式化成 “Wed, 23 Jan 2019 09:23:42 GMT”
- toISOString :格式化成 “2019-01-23T09:23:42.000Z”
如果需要自定义格式,则要自己创建。
2. 编写自定义日期格式
假设想要2019年1月23日星期四这样的日期格式。需要知道Date对象日期方法
要获取这样的格式,用到Date中的四个方法:
- getFullYear:获取当地时间4位数的年份
- getMonth:获取当时时间的月份,注意从 0 开始
- getDate:获取当地时间月中的某一天(1-31)
- getDay:获取当地时间的星期几(0-6),星期日(0)开始,到星期六(6)结束。
const d = new Date(2019, 0, 23)
const year = d.getFullYear() // 2019
const date = d.getDate() // 23
这样我们可以自己创建函数来对不同的业务逻辑进行处理
下面贴出一个具体的处理日期时间的函数,这个函数应该能够满足相当一部分的业务需求。
/**
* @param day 以今天为基准,前后几天,exp:-7——距今7天前的那天的日期;5——距离今天5天后的那天的日期
* @param opt timeType: 'local'——采用本地时间,具体到天;timeType: 不填/'UTC'——默认采用UTC时间;timeType
* @returns
*/
export function getDay (day: number, opt?: any): String {
//Date()返回当日的日期和时间。
const days = new Date()
//getTime()返回 1970 年 1 月 1 日至今的毫秒数。
const gettimes = days.getTime() + 1000 * 60 * 60 * 24 * day
//setTime()以毫秒设置 Date 对象。
days.setTime(gettimes)
const year = days.getFullYear()
let month = days.getMonth()+1 as any
if(month<10){
month = "0" + month
}
let today = days.getDate() as any
if(today<10){
today="0"+today
}
if (opt && opt.timeType === 'local') return `${year}-${month}-${today}T00:00`
if ( !opt || (opt && opt.timeType === 'UTC') )return `${year}-${month}-${today}`
}