基本概念

在计算机中,我们经常需要处理日期和时间。

这是日期:

  • 2019-11-20
  • 2020-1-1

这是时间:

  • 12:30:59
  • 2020-1-1 20:21:59

日期是指某一天,它不是连续变化的,而是应该被看成离散的。

而时间有两种概念,一种是不带日期的时间,例如,12:30:59。另一种是带日期的时间,例如,2020-1-1 20:21:59,只有这种带日期的时间能唯一确定某个时刻,不带日期的时间是无法确定一个唯一时刻的。

本地时间

当我们说当前时刻是2019年11月20日早上8:15的时候,我们说的实际上是本地时间。在国内就是北京时间。在这个时刻,如果地球上不同地方的人们同时看一眼手表,他们各自的本地时间是不同的:

localtime

所以,不同的时区,在同一时刻,本地时间是不同的。全球一共分为24个时区,伦敦所在的时区称为标准时区,其他时区按东/西偏移的小时区分,北京所在的时区是东八区。

时区

因为光靠本地时间还无法唯一确定一个准确的时刻,所以我们还需要给本地时间加上一个时区。时区有好几种表示方式。

一种是以GMT或者UTC加时区偏移表示,例如:GMT+08:00或者UTC+08:00表示东八区。

GMTUTC可以认为基本是等价的,只是UTC使用更精确的原子钟计时,每隔几年会有一个闰秒,我们在开发程序的时候可以忽略两者的误差,因为计算机的时钟在联网的时候会自动与时间服务器同步时间。

另一种是缩写,例如,CST表示China Standard Time,也就是中国标准时间。但是CST也可以表示美国中部时间Central Standard Time USA,因此,缩写容易产生混淆,我们尽量不要使用缩写。

最后一种是以洲/城市表示,例如,Asia/Shanghai,表示上海所在地的时区。特别注意城市名称不是任意的城市,而是由国际标准组织规定的城市。

因为时区的存在,东八区的2019年11月20日早上8:15,和西五区的2019年11月19日晚上19:15,他们的时刻是相同的:

timezone

时刻相同的意思就是,分别在两个时区的两个人,如果在这一刻通电话,他们各自报出自己手表上的时间,虽然本地时间是不同的,但是这两个时间表示的时刻是相同的。

夏令时

时区还不是最复杂的,更复杂的是夏令时。所谓夏令时,就是夏天开始的时候,把时间往后拨1小时,夏天结束的时候,再把时间往前拨1小时。我们国家实行过一段时间夏令时,1992年就废除了,但是矫情的美国人到现在还在使用,所以时间换算更加复杂。

daynight-saving

因为涉及到夏令时,相同的时区,如果表示的方式不同,转换出的时间是不同的。我们举个栗子:

对于2019-11-20和2019-6-20两个日期来说,假设北京人在纽约:

  • 如果以GMT或者UTC作为时区,无论日期是多少,时间都是19:00
  • 如果以国家/城市表示,例如America/NewYork,虽然纽约也在西五区,但是,因为夏令时的存在,在不同的日期,GMT时间和纽约时间可能是不一样的:
时区 2019-11-20 2019-6-20
GMT-05:00 19:00 19:00
UTC-05:00 19:00 19:00
America/New_York 19:00 20:00

实行夏令时的不同地区,进入和退出夏令时的时间很可能是不同的。同一个地区,根据历史上是否实行过夏令时,标准时间在不同年份换算成当地时间也是不同的。因此,计算夏令时,没有统一的公式,必须按照一组给定的规则来算,并且,该规则要定期更新。

注意

计算夏令时请使用标准库提供的相关类,不要试图自己计算夏令时。

本地化

在计算机中,通常使用Locale表示一个国家或地区的日期、时间、数字、货币等格式。Locale语言_国家的字母缩写构成,例如,zh_CN表示中文+中国,en_US表示英文+美国。语言使用小写,国家使用大写。

对于日期来说,不同的Locale,例如,中国和美国的表示方式如下:

  • zh_CN:2016-11-30
  • en_US:11/30/2016

计算机用Locale在日期、时间、货币和字符串之间进行转换。一个电商网站会根据用户所在的Locale对用户显示如下:

中国用户 美国用户
购买价格 12000.00 12,000.00
购买日期 2016-11-30 11/30/2016

小结

在编写日期和时间的程序前,我们要准确理解日期、时间和时刻的概念;

由于存在本地时间,我们需要理解时区的概念,并且必须牢记由于夏令时的存在,同一地区用GMT/UTC和城市表示的时区可能导致时间不同;

计算机通过Locale来针对当地用户习惯格式化日期、时间、数字、货币等。