需要知道的JS的日期,都在这了

论坛 期权论坛 期权     
大迁世界   2019-7-8 00:31   3943   0
译者:前端小智
原文:https://css-tricks.com/everything-you-need-to-know-about-date-in-javascript/
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!
JS中的 Date 很奇怪。当我们需要处理日期和时间的时候比较麻烦,经常借助像date-fns和 Moment 这样的库。
但是我们并不总是需要使用库。如果知道要注意一些总是,日期实际上可以非常简单。接下介绍有关
  1. Date
复制代码
对象的所有信息
[h1]时区[/h1]我们的世界有数百个时区。在JavaScript中,我们只关心两个, 本地时间和协调世界时(UTC)。

  • 本地时间是指你的计算机所在的时区。


  • UTC实际上是格林威治标准时间(GMT)的同义词

默认情况下,JS中的几乎每个日期方法(除了一个)都是本地时间。只有指定UTC,才能获得 UTC 时间 。
[h1]创建日期[/h1]可以使用
  1. newDate()
复制代码
来创建日期,传入的参数通常有4种常用的方式:
  • 使用日期字符串参数
  • 使用一系列的参数
  • 时间戳参数
  • 不带参数
[h3]使用日期字符串参数[/h3]
    1. new Date('1988-03-21')
    复制代码
这种方式方便且直观。
如果现在写的是
  1. 21-03-1988
复制代码
,我们可以毫不费力想表达的是1988年3月21日。但是如果用JS 编写21-03-1988,则会得到无效的日期。


这是有原因的。
在世界的不同地方以不同的方式解释日期字符串。例如
  1. 11-06-2019
复制代码
  1. 2019年6月11日
复制代码
还是
  1. 2019年11月6日
复制代码
。你不能确定我指的是哪一个,除非你知道我正在使用的日期系统。
在JS中,如果要使用日期字符串参数,则需要使用全球都能接受的格式,其中一种格式是ISO 8601扩展格式。
    1. // ISO 8601 Extended format
    复制代码
    1. `YYYY-MM-DDTHH:mm:ss:sssZ`
    复制代码
    1. YYYY
    复制代码
    :4位数年份
    1. MM
    复制代码
    :两位数月份(即 1月为01,12月为12)
    1. DD
    复制代码
    :两位数的日期(0到31)
    1. -
    复制代码
    :日期分隔符
    1. T
    复制代码
    :表示开始时间
    1. HH
    复制代码
    :24位小时数(0到23)
    1. mm
    复制代码
    :分钟(0到59)
    1. ss
    复制代码
    :秒(0到59)
    1. sss
    复制代码
    :毫秒(0到999)
    1. :
    复制代码
    :时间分隔符
    1. Z
    复制代码
    :如果存在
    1. Z
    复制代码
    ,则日期将设置为UTC,如果
    1. Z
    复制代码
    不存在,则为本地时间。
其中小时,分钟,秒和毫秒是可选的,如果你想创建一个2019年6月11日的日期,可以这样写:
    1. new Date('2019-06-11')
    复制代码
在这里要特别注意,使用日期字符串参数创建日期存在很大问题,把创建的日期打印出来就可以发现问题。
如果你住在格林威治标准时间(GMT)晚的的地区,你会得到一个日期是
  1. 6月10日
复制代码





如果你住在比格林威治标准时间早的地区,才会等得到
  1. 6月11日
复制代码
的日期。



发生这种情况是因为日期字符串参数的方法具有特殊行为:如果创建日期(未指定时间),则会获得UTC格式设置的日期。

在上面的场景中,使用
  1. newDate('2019-06-11')
复制代码
创建日期时,实际上创建的日期是2019年6月11日,UTC时间上午12点。这就是为什么住在格林尼治标准时间之后的地区的人得到的是
  1. 6月10日
复制代码
而不是
  1. 6月11日
复制代码

如果要使用日期字符串参数方法在“本地时间”中创建日期,则需要包括时间。如果包含时间,则需要至少写入
  1. HH
复制代码
  1. mm
复制代码
    1. new Date('2019-06-11T00:00')
    复制代码




使用日期字符串参数的创建的本地时间与UTC的比较可能是一个难以捕捉的错误。所以,建议不要使用日期字符串创建日期方式。
格林威治标准时间GMT 十七世纪,格林威治皇家天文台为了海上霸权的扩张计画而进行天体观测。1675年旧皇家观测所(Old Royal Observatory) 正式成立,到了1884年决定以通过格林威治的子午线作为划分地球东西两半球的经度零度。观测所门口墙上有一个标志24小时的时钟,显示当下的时间,对全球而言,这里所设定的时间是世界时间参考点,全球都以格林威治的时间作为标准来设定时间,这就是我们耳熟能详的「格林威治标准时间(Greenwich Mean Time,简称G.M.T.)的由来,标示在手表上,则代表此表具有两地时间功能,也就是同时可以显示原居地和另一个国度的时间。
世界协调时间UTC
多数的两地时间表都以GMT来表示,但也有些两地时间表上看不到GMT字样,出现的反而是UTC这3个英文字母,究竟何谓UTC?事实上,UTC指的是Coordinated Universal Time- 世界协调时间(又称世界标准时间、世界统一时间),是经过平均太阳时(以格林威治时间GMT为准)、地轴运动修正后的新时标以及以「秒」为单位的国际原子时所综合精算而成的时间,计算过程相当严谨精密,因此若以「世界标准时间」的角度来说,UTC比GMT来得更加精准。其误差值必须保持在0.9秒以内,若大于0.9秒则由位于巴黎的国际地球自转事务中央局发布闰秒,使UTC与地球自转周期一致。所以基本上UTC的本质强调的是比GMT更为精确的世界时间标准,不过对于现行表款来说,GMT与UTC的功能与精确度是没有差别的。
[h3]使用一系列的参数创建[/h3]最多可以传入七个参数来创建日期/时间。
Year:4位数年份
Month:一年中的某月(0-11)
Day:每月的某天(1-31),如果省略,则默认为1。
Hour:一天中的小时(0-23),如果省略,则默认为0。
Minutes:分钟(0-59),如果省略,则默认为0。
Seconds:秒(0-59),如果省略,则默认为0。
Milliseconds:毫秒(0-999),如果省略,则默认为0。
  1. // 11th June 2019, 5:23:59am, Local Time
复制代码
  1. new Date(2019, 5, 11, 5, 23, 59)
复制代码
许多开发人员比较少用这种方式,因为它看起来很复杂,但它实际上非常简单。可以从左到右记忆:年、月、日、小时、分钟、秒和毫秒。
Date 中需要注意的地方
  1. Month
复制代码
是从
  1. 0
复制代码
开始的,如
  1. 1月===0,2月===1,3月===2
复制代码
,依此类推。
再来一些事件熟悉一下多个参数的用法
    1. // 21st March 1988, 12am, Local Time.
    复制代码
    1. new Date(1988, 2, 21)
    复制代码

    1. // 25th December 2019, 8am, Local Time.
    复制代码
    1. new Date(2019, 11, 25, 8)
    复制代码

    1. // 6th November 2023, 2:20am, Local Time
    复制代码
    1. new Date(2023, 10, 6, 2, 20)
    复制代码

    1. // 11th June 2019, 5:23:59am, Local Time
    复制代码
    1. new Date(2019, 5, 11, 5, 23, 59)
    复制代码
注意,使用参数创建的日期都是用本地时间
使用参数的还有一个好处是不会在本地时间和UTC之间混淆,如果需要UTC时间,请以这种方式创建UTC 日期:
    1. // 11th June 2019, 12am, UTC.
    复制代码
    1. new Date(Date.UTC(2019, 5, 11))
    复制代码
[h3]使用时间戳来创建日期[/h3]在JS中,时间戳是自1970年1月1日以来经过的毫秒数(1970年1月1日也称为Unix纪元时间)。根据我的经验,很少使用时间戳来创建日期,一般使用时间戳来比较不同的日期或者格式化日期,后面在讨论。
[h3]不带参数的形式创建日期[/h3]如果创建没有任何参数的日期,则会将日期设置为当前时间(以本地时间为单位)。
    1. new Date()
    复制代码



小结一波
  • 使用 new Date() 创建日期
  • 有四种可能的语法:
  •   使用字符串日期值
  •   使用一系列参数
  •   使用时间戳
  •   不带参数
  • 最好不要使用字符串日期值的方法创建日期
  • 最好使用一系列参数方式创建日期
  • 记住月份是从0开始的
[h1]格式化日期[/h1]多数编程语言都提供了一种格式工具来创您想要的任何日期格式 例如,在PHP中,可以将
  1. date("d M Y")
复制代码
格式化成
  1. 231月2019
复制代码
这样的日期。
但是在JS 中格式化日期并不容易。
原生
  1. Date
复制代码
对象提供了七种格式化方法,这七种方法中的每一种都会给你一个特定的价值,而且它们毫无用处。
    1. const date = new Date(2019, 0, 23, 17, 23, 42)
    复制代码
  1. [/code]
  2. [code]toString
复制代码
:格式化成 "Wed Jan 23 2019 17:23:42 GMT+0800 (中国标准时间)"
  1. toDateString
复制代码
: 格式化成 "Wed Jan 23 2019"
  1. toLocaleString
复制代码
:格式化成 "2019/1/23 下午5:23:42"
  1. toLocaleDateString
复制代码
:格式化成 "2019/1/23"
  1. toGMTString
复制代码
:格式化成 "Wed, 23 Jan 2019 09:23:42 GMT"
  1. toUTCString
复制代码
:格式化成 "Wed, 23 Jan 2019 09:23:42 GMT"
  1. toISOString
复制代码
:格式化成 "2019-01-23T09:23:42.000Z"
如果需要自定义格式,则要自己创建。
[h3]编写自定义日期格式[/h3]假设想要
  1. 2019年1月23日星期四
复制代码
这样的日期格式。需要知道
  1. Date
复制代码
对象日期方法。
要获取这样的格式,用到
  1. Date
复制代码
中的四个方法:
  1. getFullYear
复制代码
:获取当地时间4位数的年份
  1. getMonth
复制代码
:获取当时时间的月份,注意从 0 开始
  1. getDate
复制代码
:获取当地时间月中的某一天(1-31)
  1. getDay
复制代码
:获取当地时间的星期几(0-6),星期日(0)开始,到星期六(6)结束。
  1. const d = new Date(2019, 0, 23)
复制代码
  1. const year = d.getFullYear() // 2019
复制代码
  1. const date = d.getDate() // 23
复制代码
因为星期和月份是从0开始的,所以我们可以创建一个映射表:
    1. const months = {
    复制代码
    1.   0: '1月',
    复制代码
    1.   1: '2月',
    复制代码
    1.   2: '3月',
    复制代码
    1.   3: '4月',
    复制代码
    1.   4: '5月',
    复制代码
    1.   5: '6月',
    复制代码
    1.   6: '7月',
    复制代码
    1.   7: '8月',
    复制代码
    1.   8: '9月',
    复制代码
    1.   9: '10月',
    复制代码
    1.   10: '11月',
    复制代码
    1.   11: '12月'
    复制代码
    1. }
    复制代码
由于月份是0开始的的,我们可以使用数组代替对象,结果一样:
    1. const months = [
    复制代码
    1.   '1月',
    复制代码
    1.   '2月',
    复制代码
    1.   '3月',
    复制代码
    1.   '4月',
    复制代码
    1.   '5月',
    复制代码
    1.   '6月',
    复制代码
    1.   '7月',
    复制代码
    1.   '8月',
    复制代码
    1.   '9月',
    复制代码
    1.   '10月',
    复制代码
    1.   '11月',
    复制代码
    1.   '12月'
    复制代码
    1. }
    复制代码
要得到1月份,你需要
    1. const monthIndex = d.getMonth()
    复制代码
    1. const monthName = months[monthIndex]
    复制代码
    1. console.log(monthName) // 1月
    复制代码
简化一下:
    1. const monthName = months(d.getMonth())
    复制代码
    1. console.log(monthName) // 1月
    复制代码
为了获取 星期四,还需要 做同样的事情:
    1. const days = [
    复制代码
    1.   '星期日',
    复制代码
    1.   '星期一',
    复制代码
    1.   '星期二',
    复制代码
    1.   '星期三',
    复制代码
    1.   '星期四',
    复制代码
    1.   '星期五',
    复制代码
    1.   '星期六'
    复制代码
    1. ]
    复制代码
获取方式:
    1. const dayName = days[d.getDay()] // 星期四
    复制代码
接着就产拼接起来。这是相对乏味的。
如果需要创建自定义格式的时间,可以使用以下方法
  1. getHours
复制代码
:获取当地时间获取小时数(0-23)。
  1. getMinutes
复制代码
:获取本地时间获取分钟(0-59)。
  1. getSeconds
复制代码
:获取本地时间获取秒数(0-59)。
  1. getMilliseconds
复制代码
:获取本地时间获取毫秒(0-999)。
[h1]日期的比较[/h1]比较日期的前后,可以直接使用
  1. >
复制代码
,
  1. =
复制代码
  1. {
复制代码
    1.   return a.getTime() === b.getTime()
    复制代码
    1. }
    复制代码

    1. const a = new Date(2019, 0, 26)
    复制代码
    1. const b = new Date(2019, 0, 26)
    复制代码
    1. console.log(isSameTime(a, b)) // true
    复制代码
    如果只想检查两个日期是否在同一天,可以比较他们的
    1. getFullYear
    复制代码
    1. getMonth
    复制代码
    1. getDate
    复制代码
    值。
      1. const isSameDay = (a, b) => {
      复制代码
      1.   return a.getFullYear() === b.getFullYear() &&
      复制代码
      1.     a.getMonth() === b.getMonth() &&
      复制代码
      1.     a.getDate()=== b.getDate()
      复制代码
      1. }
      复制代码

      1. const a = new Date(2019, 0, 26, 10) // 26 Jan 2019, 10am
      复制代码
      1. const b = new Date(2019, 0, 26, 12) // 26 Jan 2019, 12pm
      复制代码
      1. console.log(isSameDay(a, b)) // true
      复制代码
    [h1]从另一个日期获取日期[/h1]有两种可能的情况,希望从另一个日期获得一个日期。
    • 设置另一个日期特定的日期/时间值
    • 从另一个日期添加/减去增量
    [h3]设置另一个日期特定的日期/时间值[/h3]可以使用以下方法设置另一个日期的日期/时间:
      1. setFullYear
      复制代码
      : 设置年份
      1. setMonth
      复制代码
      :设置月份
      1. setDate
      复制代码
      :设置每月的某一天
      1. setHours
      复制代码
      :设置时
      1. setNubytes
      复制代码
      :设置分
      1. setSeconds
      复制代码
      :设置秒
      1. setMilliseconds
      复制代码
      :设置毫秒
    例如,如果想将日期设置为每月15日,可以使用
    1. setDate(15)
    复制代码
      1. const d = new Date(2019, 0, 10)
      复制代码
      1. d.setDate(15)
      复制代码

      1. console.log(d) // 15 January 2019
      复制代码
    注意:上面的
    1. setter
    复制代码
    方法会改变原始日期对象。在实际中,我们不应该改变对象,应该在新的日期对象上执行这些操作。
      1. const d = new Date(2019, 0, 10)
      复制代码
      1. const newDate = new Date(d)
      复制代码
      1. newDate.setMonth(5)
      复制代码

      1. console.log(d) // 10 January 2019
      复制代码
      1. console.log(newDate) // 10 June 2019
      复制代码
    [h3]从另一个日期添加/减去增量[/h3]添加/减去增量有两种通用方法。第一种方法在Stack Overflow上更受欢迎,它简洁,但更难掌握。第二种方法更冗长,但更容易理解。
    假设希望获得从今天起三天的日期。对于这个例子,假设今天是
    1. 2019年3月28日
    复制代码

    [h3]第一种方法[/h3]
      1. const today = new Date(2019, 2, 28)
      复制代码
    首先,我们创建一个新的Date对象,这样就不会改变原始日期
      1. const finalDate = new Date(today)
      复制代码
    接下来,我们需要知道要更改的值。因为我们要改变日期,所以我们可以用
    1. getDate
    复制代码
    获得日期
      1. const currentDate = today.getDate()
      复制代码
    因为获取三天后的日期,所以需要在得到的日期加3
      1. setDate(currentDate + 3)
      复制代码
    完整代码:
      1. const today = new Date(2019, 2, 28)
      复制代码
      1. const finalDate = new Date(today)
      复制代码
      1. finalDate.setDate(today.getDate() + 3)
      复制代码

      1. console.log(finalDate) // 31 March 2019
      复制代码
    [h3]第二种方法[/h3]使用
    1. getFullYear
    复制代码
    1. getMonth
    复制代码
    1. getDate
    复制代码
    方法,更改对应的值, 然后,我们使用
    1. newDate
    复制代码
    创建最终日期。
      1. const today = new Date(2019, 2, 28)
      复制代码

      1. // Getting required values
      复制代码
      1. const year = today.getFullYear()
      复制代码
      1. const month = today.getMonh()
      复制代码
      1. const day = today.getDate()
      复制代码

      1. // Creating a new Date (with the delta)
      复制代码
      1. const finalDate = new Date(year, month, day + 3)
      复制代码

      1. console.log(finalDate) // 31 March 2019
      复制代码
    [h1]自动日期校正[/h1]如果为
    1. Date
    复制代码
    提供一个超出其可接受范围的值,JS 将自动重新计算日期。
    如下所示,假设我们把日期定在2019年3月33日,日历上没有33日,JS 会自动将
    1. 3月33日
    复制代码
    调整为
    1. 4月2日
    复制代码



    这意味着在创建增量时无需担心计算分钟,小时,天,月等,JavaScript会自动处理。

    交流
    我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!
    关注公众号,后台回复福利,即可看到福利,你懂的。

    延伸阅读
    2019年,Fluter 和 React Native 谁主沉浮
    ES10目前可以使用的5个新特性
    搞懂JavaScript引擎运行原理


  • 分享到 :
    0 人收藏
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    积分:20
    帖子:4
    精华:0
    期权论坛 期权论坛
    发布
    内容

    下载期权论坛手机APP