Time Zone, Leap Year, Date Format, Epoch Time 时区, 闰年, 日期格式
前言
以前有写过一篇了, 但很乱, 这篇就作为它的整理版吧.
Leap Year 闰年
闰年是指那些有 366 天, 二月份有 29号 的年份. 比如 2020年 有 2月29日, 所以 2020 就是闰年.
why leap year?
地球自转一圈是一天, 地球绕太阳转一圈是一年. 地球绕太阳转一圈的同时, 地球一共自转了 365 圈, 所以就是 365 天.
这个计算并不精准, 因为地球并不是刚刚好转 365 圈的, 其实是超过的. 正确的天数是 365天5小时48分46秒
于是, 如果按 365 天计, 每一年就少了 5 小时多. 每四年就少了一天. 久了就越差越远了.
所以必须弥补回来, 最简单的方式是, 每四年补回一天. 这样就准了
四年一闰, 百年不闰, 四百年再闰
但仔细计算会发现, 每四年加一天是有多的. 久而久之也会不精准, 于是最终就变成了大家熟悉的四年一闰, 百年不闰, 四百年再闰.
console.log(new Date('1900-02-29').toLocaleDateString('en-MY')); // 01/03/1900 没有 因为百年不闰 console.log(new Date('1904-02-29').toLocaleDateString('en-MY')); // 29/02/1904 有, 因为四年一润 console.log(new Date('1908-02-29').toLocaleDateString('en-MY')); // 29/02/1908 有, 因为四年一润 console.log(new Date('2000-02-29').toLocaleDateString('en-MY')); // 29/02/2000 有, 因为四百年再润
每四年调一次, 100 年又调一次, 400 年又调一次. 所以时间一直都是有微差的 (但很小很小), 直到 400 年才对准.
Time Zone 时区
世界各地的时间很奇妙, 比如跨年都是在 12月31号 晚上 11:59分 放烟花庆祝. 但是美国的晚上是马来西亚的白天 (因为彼此在地球的另一端, 一个面向太阳, 另一个就是夜晚)
如果用统一时间的话, 会有两个后果, 第一, 马来西亚人只能在白天放烟花庆祝新年, 第二, 马来西亚人必须在 12月31号 下午 3:59分 倒数跨年. 显然这两个都不可能被接受. 所以不同的地区必须要有不同的时间 (时区).
但统一时间任然是有必要的, 不然跨国沟通也会有问题, 所以除了时区, 我们也有统一的时间 UTC/GMT (它以英国时区为标准, 为什么是英国呢? 因为这个标准是在大英帝国时代定下的)
例子:
马来西亚的时区是 Malaysia Standard Time 它的 offset 是 +08.00 对应英国的 UTC +00:00 快了 8 小时. 也就是说马来西亚活在未来 8 小时.
时区是国家规定的, 而且是可以改的...
马来西亚的时区以前是 +07:30 后来换成了 +08:00. 这种修改很容易引起 Bug. 因为我们普遍会认为 offset = timezone.
但其实 timezone 指的是一个规则. 里面可能包含了许多不同的 offset.
const time1 = new Date(1981, 1, 1); console.log(time1.toUTCString()); // Sat, 31 Jan 1981 16:30:00 GMT console.log(time1.getTimezoneOffset()); // -450 const time2 = new Date(1982, 1, 1); console.log(time2.toUTCString()); // Sun, 31 Jan 1982 16:00:00 GMT console.log(time2.getTimezoneOffset()); // -480 多了 30 minutes
JS 的 Date 包含了 timezone 里所有不同年份的历史 offset 哦.
时区小知识:
整个地球分为 24 个时区, 从 -12:00 到 +13:00
UTC (Universal Time Coordinated) 全球统一时间 +00:00, 也是英国伦敦的时间
GMT(Greenwich Mean Time) UTC 的前生, 现在都叫 UTC 了.
PST (Pacific Standard Time -08:00) 也是很常见的时区. 美国, 加拿大那一带用的
DST ( Daylight Saving Time 夏令时) 夏令时是一个机制, 为了节约能源, 它的做法是在夏季左右把时间调后一小时, 然后又在夏季结束后调前一小时, 这个规则也是通过时区管理的.
例子: "Sun Mar 09 2014 01:59:00 GMT-0500 (EST)" ->
"Sun Mar 09 2014 03:00:00 GMT-0400 (EDT)". 两点钟消失了, 因为时间被调后了一小时, offset 从 -0500 变成了 -0400.
日期格式
不同国家除了时区不一样, 日期的格式也有很多区别.
new Date().toLocaleString('en-US'); // 1/15/2023, 2:13:33 PM new Date().toLocaleString('zh-TW'); // 2023/1/15 下午2:13:33 new Date().toLocaleString('ms-MY'); // 15/1/2023, 2:13:33 PTG
美国的格式是 1/15/2023 月/日/年, pm 代表晚上
台湾是 2023/1/15 年/月/日
马来西亚是 15/1/2023 日/月/年 PTG 是 petang 马来语, 下午的意思
这些格式最烦人的就是日和月经常会分不清.
程序员比较喜欢和常看见的格式是
new Date().toISOString(); // 2023-01-15T06:19:08.034Z new Date().toUTCString(); // Sun, 15 Jan 2023 06:19:08 GMT
ISO : 年-月-日 z 表示时区是 UTC
UTC/GMT 用了 Jan 来表示月份, 这样就不容易和日搞混了.
注:语言和格式 (排位顺序),都会收地域的影响。
字符
日期格式可以用一些字符来表达 (不同语言可能有微差, 但基本规则是一致的)
比如 C# 的 yyyy-MMM-dd hh:mm:ss tt 表示 年-月-日 时:分:秒: am/pm
规则有三个特点
1. 缩写, y 是 year 的缩写, s 是 second 的缩写
2. 大小写, month 和 minutes 的缩写都是 m, 所以需要靠大小写来区分, M 代表 month, m 代表 minute.
3. 数量 d 表示最少显示一位数, dd 表示最少两位数. 比如一号, d=1, dd=01, 11号则是一样的 d=11, dd=11
常用:
yy = 23
yyyy = 2023
M = 1, 11
MM = 01, 11
MMM = Jan, Nov (文字)
MMMM = January, November
d = 1, 11
dd = 01, 11
ddd = Mon (星期几)
dddd = Monday
H = 1, 13 (24小时制)
HH = 01, 13
h = 1, 1
hh = 01, 01
m = 1
mm = 01
s = 1
ss = 01
tt = AM/PM (其它语言可能不一样)
K = +08:00 (其它语言可能不一样)
Epoch Time
0001 年是耶稣诞生的年份, 1970 年是 Unix 诞生的年份.
Epoch Time 指的就是 1970年1月1 号. JavaScript Date.getTime 返回的就是 1970年1月1号到指定 datetime 的毫秒数.