16

软件中的时间问题

 3 years ago
source link: https://insights.thoughtworks.cn/datetime-in-software-development/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

DDD中最重要的一个过程就是统一语言。和客户沟通时间问题的时候,可以先把一些时间的概念统一一下。

每天早上9:00到公司,迟到要罚款;中午12:00去吃饭,慢了好吃的就没有了;晚上18:00要回家,晚了老婆不开心。

我们熟练的使用着时间,毕竟小学二年级课本上就开始讲时间了。

可时间究竟是什么?

  • 哲学家认为过去、现在、未来等时间概念只不过是人的幻觉。
  • 牛顿说:绝对钟的读数就是时间。
  • 爱因斯坦说,时间和空间一起,构成了被称为时空的实体。

看看大神的答案,本来可以理解的时间,一下子就糊涂了。人类文明探索了几千年,微观上看到了夸克交子,宏观上找到了黑洞,但是面对时间我们仍然不能给出确定的答案。

地球上的时间

大神考虑的内容要么是心理的,要么是宇宙的,要么就是微观的。其实我们了解地球上的时间就够了。

VzIBRfm.jpg!mobile

一般人都知道时区:为了克服时间上的混乱,1884年在华盛顿召开的一次国际经度会议上,规定将全球划分为24个时区(东、西各12个时区)。

客户的疑问

有了时区,已经可以解决地球上一般问题了。但是面对全球业务的客户,他们还是会提出很多问题:

  1. 为什么要问我使用哪个时区显示时间?上游发给我们什么就显示什么呀?
  2. 计算两个时间差几天,为什么需要选择使用哪个时区?(客户的规则2019-01-01 23:59:59到2019-01-02 00:00:00,算一天)
  3. 上游给了时间和时区两个字段,我们存下来后,数据库里面显示也是正常的,为什么就没有时区了?

DDD中最重要的一个过程就是 统一语言 。和客户沟通时间问题的时候,可以先把一些时间的概念统一一下。

给客户建立这样的时间概念:

本地时间、时区、时区时间、绝对时间

  • 本地时间:一般人讲的时间都是本地时间,它只在当地有效。类似2019-12-24 10:22,北京的这个时间和伦敦的这个时间可不是一个时间。

  • 时区:使用相同本地时间的区域。类似Asia/Shanghai,America/Havana,为了便于理解我经常标记为UTC+8,UTC-8,这两种标记方法并不等效,不是一个概念,客户一般不关心这个,不用说,程序员自己心里明白就好,后面讲差别。

  • 时区时间:带有时区的时间,可以认为是可读的绝对时间。类似2019-12-24 10:22 (Asia/Shanghai),同样我也会写成2019-12-24 10:22 UTC+8,因为带有了时区信息,这些时间就可以在不同时区间转换了。

  • 绝对时间:也可以叫时间戳,是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。尽量少讲绝对时间,有些客户不太理解这个。

有一次我这样和客户讲:我们在北京看到的12点是北京时间12点,在伦敦看到的12点是伦敦的12点,那么如果我们在月球,看到的12点是什么呢?所以脱离了地球的24个时区,时间还是存在的,这种不因时区而变化的时间就是绝对时间。

有了这些基本概念后,围绕着这些基本概念解答问题,而且主要以 举例子 的形式讲解。

  • 问题1 :不同时区显示的时间不同,比如如果一个货物是在英国中午12:00发货,此时是中国的20:00,那么一个中国用户想要看到的是12:00还是20:00呢?

如果客户选择12:00,说明用户关心本地时间,系统应该使用事件发生地时区显示时间;

如果客户选择20:00,说明用户关心绝对时间,但是绝对时间没法显示,还是要选择一个时区,所以使用用户最舒服的时区,他自己的时区。

  • 问题2 :客户问这个问题,十有八九是以为时区只影响时间,忘记了“日期变更线”,可以举一个极端的例子,举例子的时候时间一定要带上时区。

2019-01-01 23:59:59 UTC+8到2019-01-02 00:00:00 UTC+8,中间差一天;如果转换时区到UTC+7,就变成了2019-01-01 22:59:59 UTC+7到2019-01-01 23:00:00 UTC+7,中间差0天了。

VfMZruv.jpg!mobile

  • 问题3 :这个问题非常有挑战,用户都说到“数据库”了。看起来不把时间戳讲一讲是搞不定了,实际上客户真的不太理解时间戳。时间戳、绝对时间都非常的技术,客户接受不了。当需要表达时间戳的时候,我一般说成是格林尼治时间,我们把所有时间都转换成0时区的时间保存了,这样比较方便比较。

客户追问:把本地时间和时区放在一起得到的数据,这个数据里面一定有时区呀?

答:这个过程就像2+8=10,但是通过10,无法找到2和8。计算机在存储绝对时间时做了类似的事情。

总结下来和客户沟通的主要手段就是: 统一语言加举例子

程序员的时间

常见问题

1.java.util.TimeZone和java.time.ZoneId,这两个东西干什么的?有什么区别?

  • TimeZone是JDK7以前的原生时区,ZoneId是JDK8以后的原生时区。他们功能是一样的,ZoneId是从joda-time到jdk里面来踢场子的。

  • TimeZone提供了toZoneId(),ZoneId没有提供toTimeZone(),但是TimeZone提供了getTimeZone(ZoneId),看来ZoneId比TimeZone更为基础,推荐使用ZoneId。

2.Australia/Canberra 和 UTC+11:00有什么区别?

  • 在提到时区的时候,我们会想到Australia/Canberra或者UTC+11:00,但是这两个东西并不等价。UTC+11:00其实是偏移量,与任何国家不相干,对应固定的经度区间,157度30分~172度30分;Australia/Canberra是行政时区,采用相同时区的地区,在地理位置上的偏移量可能不同,中国跨越了5个时区,但是全国还是统一使用UTC+8;有些国家的政策也可能调整,具体的偏移量也会变,采用夏令时的地区每年都会变,具体什么时间调整也是政策决定的。

OffsetDateTime对应UTC+11:00,固定偏移量;ZonedDateTime对应Australia/Canberra,偏移量不一定是固定的,对于Australia/Canberra一般是UTC+11,有时也会变成UTC+10。

  • 下面demo中同一个Zone的两个时间2015-10-04 01:00和2015-10-04 03:00,使用了不同的时区,看起来相差两小时,实际上仅仅相差1小时。
ZoneId zoneId = ZoneId.of("Australia/Canberra");
ZonedDateTime start = LocalDateTime.of(2015, 10, 4, 1, 0)
      .atZone(zoneId);
ZonedDateTime end = LocalDateTime.of(2015, 10, 4, 3, 0)
      .atZone(zoneId);
System.out.println(MessageFormat.format("Start:\t{0}\nEnd:\t{1}\nDuration:\t{2}",
start, end, Duration.between(start, end)));

输出结果为

Start:2015-10-04T01:00+10:00[Australia/Canberra]
End:2015-10-04T03:00+11:00[Australia/Canberra]
Duration:PT1H

所以使用类似Australia/Canberra的这种ZoneRegion才能得到真正可靠的本地时间。

3.ZonedDateTime vs OffsetDateTime

  • ZonedDateTime提供了toOffsetDateTime(),OffsetDateTime也提供了toZonedDateTime(),他们互惠互利,互通有无,和睦相处。但是,一个ZonedDateTime在经历了toOffsetDateTime()、toZonedDateTime()再回到ZonedDateTime的时候已经不是原来的ZonedDateTime了,它把它原来的Australia/Canberra弄丢了。所以不要随便toOffsetDateTime()。

4. GMT vs UTC

GMT,格林尼治标准时间(旧译“格林威治平均时间”或“格林威治标准时间”)是指位于伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。

协调世界时(UTC) 英文:Coordinated Universal Time ,别称:世界统一时间,世界标准时间,国际协调时间, 协调世界时,又称世界统一时间,世界标准时间,国际协调时间,简称UTC。

GMT的历史比UTC悠久,UTC出现后GMT就开始参考UTC时间,基本可以认为GMT=UTC。

5.Restful接口中建议使用Date、String、long来保存时间

com.alibaba.fastjson.JSON可以正常的将java.time中内容正确的保存和读取到json中;

com.fasterxml.jackson.databind.ObjectMapper保存的结果不理想。因此建议在restful接口中继续使用原始类型。

更多精彩洞见,请关注微信公众号:ThoughtWorks洞见


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK