拨开时间的迷雾

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

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

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

可时间究竟是什么?

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

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

地球上的时间

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

image

一般人都知道时区:为了克服时间上的混乱,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天了。

image
  • 问题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高玉山

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容