DateTime 总结

  1. 1. 🥇 日期/时间及时区
    1. 1.1. 🥈 先从 GMT 说起吧
    2. 1.2. 🥈 UTC
    3. 1.3. 🥈 CST
  2. 2. 🥇 日期 / 时间及格式
    1. 2.1. 🥈 RFC 2822
    2. 2.2. 🥈 ISO 8601
      1. 2.2.1. 🔅 日期表示法
      2. 2.2.2. 🔅 时间表示法
      3. 2.2.3. 🔅 日期时间表示法
    3. 2.3. 🥈 Unix Timestamp
    4. 2.4. 🥈 其它表示法
      1. 2.4.1. RFC 850
      2. 2.4.2. ANSI C’s asctime() format
  3. 3. 🥇 系统时间及时区
    1. 3.1. 🥈 NSTimeZone
    2. 3.2. 🥈 NSLocale
  4. 4. 🥇 各语言中的一些表示法
    1. 4.1. 🥈 HTTP Date
    2. 4.2. 🥈 JavaScript
    3. 4.3. 🥈 Ruby
    4. 4.4. 🥈 Obj-C
  5. 5. REF::

datetime

每个程序员都用过 DateTime,但真正当前后台进行交互时,才发现这里的复杂性。比如有这么一些关键词:

  • GMT
  • UT/UTC
  • CST
  • RFC 1123
  • ISO 8601
  • Unix Timestamp

还有在常见系统中对应的:

  • TimeZone
  • Local

🥇 日期/时间及时区

🥈 先从 GMT 说起吧

(Greenwich Mean Time,GMT)是指位于英国伦敦郊区的皇家格林威治天文台的标准时间。
通俗的说,就是将地球按经度分成 24 个区,每个区有自己当下时间,比如中国就在东 8 区,代号 +8。向东走一个区(日本,东九区),手表就要调快一个小时。

🥈 UTC

Coordinated Universal Time,简称 UTC(世界标准时间或世界协调时间)

很多时间被称作 UTC,但 RFC 中均使用 UT 来对比 GMT。

GMT 并不精准,于是以 GMT 为准加上修正而成的时间,被称作为 UT,一般对于我们来说,这两个值没有差别。另外,早年的 PC 好像都是 GMT,后来就换成了 UT 时间。

🥈 CST

China Standard Time (中国标准时间),也就是我们每天所说的北京时间,我国是属东八区,转成 UTC,加上 +8 的时区表示即可。


🥇 日期 / 时间及格式

最后来看下关健性的一个,有了时间,但是在不同国家,不同人群,不同设备之间交流时,用什么样的格式呢。

🥈 RFC 2822

互联网协议 RFC 1123 的子集: RFC 2822 Internet Message Format(前身 RFC 822 )制定最新的日期/时间格式。

1
2
3
Thu, 07 Jul 2016 02:40:59 GMT
# 对应东 8 区时间
Thu, 07 Jul 2016 10:40:59 +0800

🥈 ISO 8601

其代表着日期和时间的表示方法,全名为《数据存储和交换形式·信息交换·日期和时间的表示方法》。

RFC 1123 中的日期/时间定义实在是太糟糕了。它很难阅读,又很难解析,以英语为背景,并且使用的是 GMT 而非 UTC。

在 RFC 822 发布后,ISO 8601 便成为了事实协议标准,它更容易理解和使用。

目前最新为第三版 ISO8601:2004

如果有可能,请在任何地方使用这种标准

🔅 日期表示法

年为 4 位数,月、日为 2 位数,例如 2004 年 5 月 3 日可写成

1
2
3
2004-05-03
# 或
20040503

🔅 时间表示法

小时、分和秒都用 2 位数表示。在 UTC 标准时区(+0)最后加一个大写字母 Z,而其他时区用实际时间加时差表示。

下午 2点 30分 50秒 表示为

1
2
3
4
5
6
7
8
9
10
11
# UTC 标准时区
14:30:50Z
# 或
143050Z

# 北京时区表示为
22:30:50+08:00
# 或
223050+0800
# 或
223050+08

🔅 日期时间表示法

时间和日期一起表示时,中间用 T 分隔。

比如下面的几个表示法:

** > UTC 标准时区(+0)**

1
2
3
2016-05-20T08:01:01+00:00
# 可以用 Z 表示 +00:00
2016-05-20T08:01:01Z

** > 北京时区表示法 **

1
2
3
2016-05-20T16:01:01+08:00
# 简化为
20160520T160101+08

** > 精确表示法 **

1
2016-05-20T16:01:01.000+08:00

其中的 .000 是秒后面的小数点,找到这个解释不容易,感谢 #SO - What does the “.000Z” mean?

🥈 Unix Timestamp

也被称作 时间戳,它是 GMT 1970年 01月 01日 00时 00分 00秒 起至现在的总秒数。看起来是这样子的:1401200885364

时间戳 0 按照 ISO 8601 格式写出来为 1970-01-01T00:00:00Z

另外,Timestamp 是现在时间相对于标准 0时 之间的秒数,是没有时区的概念的。

这种格式在使用起来比较简单,如果不表示 1970 年之前的时间的话,但可读性却也是最差的,所以在 API 中很少有看到这种表示法。(开发者也是 API 的最大用户,可读性很重要。)

🥈 其它表示法

RFC 850

obsoleted by RFC 1036

1
Sunday, 06-Nov-94 08:49:37 GMT

ANSI C’s asctime() format

1
Sun Nov 6 08:49:37 1994

🥇 系统时间及时区

那系统又是如何定义当地时间呢?以 iOS 为例:

在 iPhone 中有 2 样东西关系到国际化,当然也关系到时间表示。其中就是 Local 和 TimeZone。

  • Local 中可以设置系统的国家,语言、系统默认语言,日期的一些属性,如定义常用格式,如 Short/Medium/Long/Full 等等。
  • TimeZone 是指当前时区,可以手动设置,也可以让系统自己网络获取。

datetime

🥈 NSTimeZone

通过 Default 取系统时区,可以看到当前为 Shanghai +8

1
2
[NSTimeZone defaultTimeZone]
Asia/Shanghai (GMT+8) offset 28800

🥈 NSLocale

NSLocale 中配置着用户的本地化信息,如货币,语言,时间表示

🥇 各语言中的一些表示法

🥈 HTTP Date

https://tools.ietf.org/html/rfc2616#section-3.3

Parses date as an HTTP-date defined by RFC 2616 and converts it to a Time object.

Returns a string which represents the time as RFC 1123 date of HTTP-date defined by RFC 2616:

day-of-week, DD month-name CCYY hh:mm:ss GMT

Note that the result is always UTC (GMT).

1
Thu, 07 Jul 2016 02:36:59 GMT

🥈 JavaScript

ECMA 5 更新为 ISO8601,老的版本用的还是 GMT 的表示法,

1
2
3
4
5
6
7
8
let n = new Date();
console.log(n);

Wed Jul 06 2014 20:00:00 GMT+0800 (CST)

# to ISO8691
console.log(n.toISOString());
2016-07-06T14:18:34.791Z

Node v6

1
2
3
4
5
6
let n = new Date();
console.log(n);

2016-07-06T14:20:54.519Z

# 如果我想把 Z 转成 +8 呢?

🥈 Ruby

Ruby 也是在某一个版本后将日期时间标准升级为 ISO8601 的,具体哪个版本无法查证。

1
2
3
4
5
require "date"

puts DateTime.now

# 2016-07-06T23:01:53+08:00

如果我想把 +8 转成 Z 呢?

🥈 Obj-C

iOS 中 Debug 时显示的时间是用 CTS 表示的,Watch 中可以看到 2014-05-25 10:29:04 CST
打印出来又是这样子的,被转成了 UTC +0 时区标准时间 2014-05-25 02:29:04 +0000

然后在具体使用时,再加上当前的时区,转换成当地时间进行显示,iOS 中可以这样转换:

1
2
3
4
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.locale = [NSLocale currentLocale];
formatter.timeZone = [NSTimeZone defaultTimeZone];
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'Z'";

REF::