DDD中最重要的一個(gè)過(guò)程就是統(tǒng)一語(yǔ)言盔夜。和客戶溝通時(shí)間問(wèn)題的時(shí)候负饲,可以先把一些時(shí)間的概念統(tǒng)一一下堤魁。
每天早上9:00到公司,遲到要罰款返十;中午12:00去吃飯妥泉,慢了好吃的就沒(méi)有了;晚上18:00要回家洞坑,晚了老婆不開(kāi)心盲链。
我們熟練的使用著時(shí)間,畢竟小學(xué)二年級(jí)課本上就開(kāi)始講時(shí)間了迟杂。
可時(shí)間究竟是什么刽沾?
- 哲學(xué)家認(rèn)為過(guò)去、現(xiàn)在逢慌、未來(lái)等時(shí)間概念只不過(guò)是人的幻覺(jué)悠轩。
- 牛頓說(shuō):絕對(duì)鐘的讀數(shù)就是時(shí)間。
- 愛(ài)因斯坦說(shuō)攻泼,時(shí)間和空間一起火架,構(gòu)成了被稱為時(shí)空的實(shí)體。
看看大神的答案忙菠,本來(lái)可以理解的時(shí)間何鸡,一下子就糊涂了。人類文明探索了幾千年牛欢,微觀上看到了夸克交子骡男,宏觀上找到了黑洞,但是面對(duì)時(shí)間我們?nèi)匀徊荒芙o出確定的答案傍睹。
地球上的時(shí)間
大神考慮的內(nèi)容要么是心理的隔盛,要么是宇宙的,要么就是微觀的拾稳。其實(shí)我們了解地球上的時(shí)間就夠了吮炕。
一般人都知道時(shí)區(qū):為了克服時(shí)間上的混亂,1884年在華盛頓召開(kāi)的一次國(guó)際經(jīng)度會(huì)議上访得,規(guī)定將全球劃分為24個(gè)時(shí)區(qū)(東龙亲、西各12個(gè)時(shí)區(qū))。
客戶的疑問(wèn)
有了時(shí)區(qū)悍抑,已經(jīng)可以解決地球上一般問(wèn)題了鳄炉。但是面對(duì)全球業(yè)務(wù)的客戶,他們還是會(huì)提出很多問(wèn)題:
- 為什么要問(wèn)我使用哪個(gè)時(shí)區(qū)顯示時(shí)間搜骡?上游發(fā)給我們什么就顯示什么呀拂盯?
- 計(jì)算兩個(gè)時(shí)間差幾天,為什么需要選擇使用哪個(gè)時(shí)區(qū)记靡?(客戶的規(guī)則2019-01-01 23:59:59到2019-01-02 00:00:00磕仅,算一天)
- 上游給了時(shí)間和時(shí)區(qū)兩個(gè)字段珊豹,我們存下來(lái)后,數(shù)據(jù)庫(kù)里面顯示也是正常的榕订,為什么就沒(méi)有時(shí)區(qū)了店茶?
DDD中最重要的一個(gè)過(guò)程就是統(tǒng)一語(yǔ)言。和客戶溝通時(shí)間問(wèn)題的時(shí)候劫恒,可以先把一些時(shí)間的概念統(tǒng)一一下贩幻。
給客戶建立這樣的時(shí)間概念:**本地時(shí)間、時(shí)區(qū)两嘴、時(shí)區(qū)時(shí)間丛楚、絕對(duì)時(shí)間
**。
本地時(shí)間:一般人講的時(shí)間都是本地時(shí)間憔辫,它只在當(dāng)?shù)赜行ばn愃?019-12-24 10:22,北京的這個(gè)時(shí)間和倫敦的這個(gè)時(shí)間可不是一個(gè)時(shí)間贰您。
時(shí)區(qū):使用相同本地時(shí)間的區(qū)域坏平。類似Asia/Shanghai,America/Havana,為了便于理解我經(jīng)常標(biāo)記為UTC+8,UTC-8锦亦,這兩種標(biāo)記方法并不等效舶替,不是一個(gè)概念,客戶一般不關(guān)心這個(gè)杠园,不用說(shuō)顾瞪,程序員自己心里明白就好,后面講差別抛蚁。
時(shí)區(qū)時(shí)間:帶有時(shí)區(qū)的時(shí)間陈醒,可以認(rèn)為是可讀的絕對(duì)時(shí)間。類似2019-12-24 10:22 (Asia/Shanghai),同樣我也會(huì)寫(xiě)成2019-12-24 10:22 UTC+8瞧甩,因?yàn)閹в辛藭r(shí)區(qū)信息钉跷,這些時(shí)間就可以在不同時(shí)區(qū)間轉(zhuǎn)換了。
絕對(duì)時(shí)間:也可以叫時(shí)間戳亲配,是指格林威治時(shí)間1970年01月01日00時(shí)00分00秒(北京時(shí)間1970年01月01日08時(shí)00分00秒)起至現(xiàn)在的總秒數(shù)尘应。盡量少講絕對(duì)時(shí)間惶凝,有些客戶不太理解這個(gè)吼虎。
有一次我這樣和客戶講:我們?cè)诒本┛吹降?2點(diǎn)是北京時(shí)間12點(diǎn),在倫敦看到的12點(diǎn)是倫敦的12點(diǎn)苍鲜,那么如果我們?cè)谠虑蛩蓟遥吹降?2點(diǎn)是什么呢?所以脫離了地球的24個(gè)時(shí)區(qū)混滔,時(shí)間還是存在的洒疚,這種不因時(shí)區(qū)而變化的時(shí)間就是絕對(duì)時(shí)間歹颓。
有了這些基本概念后,圍繞著這些基本概念解答問(wèn)題油湖,而且主要以舉例子的形式講解巍扛。
- 問(wèn)題1:不同時(shí)區(qū)顯示的時(shí)間不同,比如如果一個(gè)貨物是在英國(guó)中午12:00發(fā)貨乏德,此時(shí)是中國(guó)的20:00撤奸,那么一個(gè)中國(guó)用戶想要看到的是12:00還是20:00呢?
如果客戶選擇12:00喊括,說(shuō)明用戶關(guān)心本地時(shí)間胧瓜,系統(tǒng)應(yīng)該使用事件發(fā)生地時(shí)區(qū)顯示時(shí)間;
如果客戶選擇20:00郑什,說(shuō)明用戶關(guān)心絕對(duì)時(shí)間府喳,但是絕對(duì)時(shí)間沒(méi)法顯示,還是要選擇一個(gè)時(shí)區(qū)蘑拯,所以使用用戶最舒服的時(shí)區(qū)钝满,他自己的時(shí)區(qū)。
- 問(wèn)題2:客戶問(wèn)這個(gè)問(wèn)題强胰,十有八九是以為時(shí)區(qū)只影響時(shí)間舱沧,忘記了“日期變更線”,可以舉一個(gè)極端的例子偶洋,舉例子的時(shí)候時(shí)間一定要帶上時(shí)區(qū)熟吏。
2019-01-01 23:59:59 UTC+8到2019-01-02 00:00:00 UTC+8,中間差一天;如果轉(zhuǎn)換時(shí)區(qū)到UTC+7玄窝,就變成了2019-01-01 22:59:59 UTC+7到2019-01-01 23:00:00 UTC+7牵寺,中間差0天了。
- 問(wèn)題3:這個(gè)問(wèn)題非常有挑戰(zhàn)恩脂,用戶都說(shuō)到“數(shù)據(jù)庫(kù)”了帽氓。看起來(lái)不把時(shí)間戳講一講是搞不定了俩块,實(shí)際上客戶真的不太理解時(shí)間戳黎休。時(shí)間戳、絕對(duì)時(shí)間都非常的技術(shù)玉凯,客戶接受不了势腮。當(dāng)需要表達(dá)時(shí)間戳的時(shí)候,我一般說(shuō)成是格林尼治時(shí)間漫仆,我們把所有時(shí)間都轉(zhuǎn)換成0時(shí)區(qū)的時(shí)間保存了捎拯,這樣比較方便比較。
客戶追問(wèn):把本地時(shí)間和時(shí)區(qū)放在一起得到的數(shù)據(jù)盲厌,這個(gè)數(shù)據(jù)里面一定有時(shí)區(qū)呀署照?
答:這個(gè)過(guò)程就像2+8=10祸泪,但是通過(guò)10,無(wú)法找到2和8建芙。計(jì)算機(jī)在存儲(chǔ)絕對(duì)時(shí)間時(shí)做了類似的事情没隘。
總結(jié)下來(lái)和客戶溝通的主要手段就是:統(tǒng)一語(yǔ)言加舉例子。
程序員的時(shí)間
常見(jiàn)問(wèn)題
1.java.util.TimeZone和java.time.ZoneId禁荸,這兩個(gè)東西干什么的升略?有什么區(qū)別?
TimeZone是JDK7以前的原生時(shí)區(qū)屡限,ZoneId是JDK8以后的原生時(shí)區(qū)品嚣。他們功能是一樣的,ZoneId是從joda-time到j(luò)dk里面來(lái)踢場(chǎng)子的钧大。
TimeZone提供了toZoneId()翰撑,ZoneId沒(méi)有提供toTimeZone(),但是TimeZone提供了getTimeZone(ZoneId),看來(lái)ZoneId比TimeZone更為基礎(chǔ)啊央,推薦使用ZoneId眶诈。
2.Australia/Canberra 和 UTC+11:00有什么區(qū)別?
- 在提到時(shí)區(qū)的時(shí)候瓜饥,我們會(huì)想到Australia/Canberra或者UTC+11:00逝撬,但是這兩個(gè)東西并不等價(jià)。UTC+11:00其實(shí)是偏移量乓土,與任何國(guó)家不相干宪潮,對(duì)應(yīng)固定的經(jīng)度區(qū)間,157度30分~172度30分;Australia/Canberra是行政時(shí)區(qū)趣苏,采用相同時(shí)區(qū)的地區(qū)狡相,在地理位置上的偏移量可能不同,中國(guó)跨越了5個(gè)時(shí)區(qū)食磕,但是全國(guó)還是統(tǒng)一使用UTC+8;有些國(guó)家的政策也可能調(diào)整尽棕,具體的偏移量也會(huì)變,采用夏令時(shí)的地區(qū)每年都會(huì)變彬伦,具體什么時(shí)間調(diào)整也是政策決定的滔悉。
OffsetDateTime對(duì)應(yīng)UTC+11:00,固定偏移量单绑;ZonedDateTime對(duì)應(yīng)Australia/Canberra回官,偏移量不一定是固定的,對(duì)于Australia/Canberra一般是UTC+11询张,有時(shí)也會(huì)變成UTC+10孙乖。
- 下面demo中同一個(gè)Zone的兩個(gè)時(shí)間2015-10-04 01:00和2015-10-04 03:00浙炼,使用了不同的時(shí)區(qū)份氧,看起來(lái)相差兩小時(shí)唯袄,實(shí)際上僅僅相差1小時(shí)。
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)));
輸出結(jié)果為
Start:2015-10-04T01:00+10:00[Australia/Canberra]
End:2015-10-04T03:00+11:00[Australia/Canberra]
Duration:PT1H
所以使用類似Australia/Canberra的這種ZoneRegion才能得到真正可靠的本地時(shí)間蜗帜。
3.ZonedDateTime vs OffsetDateTime
- ZonedDateTime提供了toOffsetDateTime(),OffsetDateTime也提供了toZonedDateTime()恋拷,他們互惠互利,互通有無(wú)厅缺,和睦相處蔬顾。但是,一個(gè)ZonedDateTime在經(jīng)歷了toOffsetDateTime()湘捎、toZonedDateTime()再回到ZonedDateTime的時(shí)候已經(jīng)不是原來(lái)的ZonedDateTime了诀豁,它把它原來(lái)的Australia/Canberra弄丟了。所以不要隨便toOffsetDateTime()窥妇。
4.GMT vs UTC
GMT舷胜,格林尼治標(biāo)準(zhǔn)時(shí)間(舊譯“格林威治平均時(shí)間”或“格林威治標(biāo)準(zhǔn)時(shí)間”)是指位于倫敦郊區(qū)的皇家格林尼治天文臺(tái)的標(biāo)準(zhǔn)時(shí)間,因?yàn)楸境踝游缇€被定義在通過(guò)那里的經(jīng)線活翩。
協(xié)調(diào)世界時(shí)(UTC) 英文:Coordinated Universal Time 烹骨,別稱:世界統(tǒng)一時(shí)間,世界標(biāo)準(zhǔn)時(shí)間材泄,國(guó)際協(xié)調(diào)時(shí)間沮焕, 協(xié)調(diào)世界時(shí),又稱世界統(tǒng)一時(shí)間拉宗,世界標(biāo)準(zhǔn)時(shí)間峦树,國(guó)際協(xié)調(diào)時(shí)間,簡(jiǎn)稱UTC旦事。
GMT的歷史比UTC悠久空入,UTC出現(xiàn)后GMT就開(kāi)始參考UTC時(shí)間,基本可以認(rèn)為GMT=UTC族檬。
5.Restful接口中建議使用Date歪赢、String、long來(lái)保存時(shí)間
com.alibaba.fastjson.JSON可以正常的將java.time中內(nèi)容正確的保存和讀取到j(luò)son中单料;
com.fasterxml.jackson.databind.ObjectMapper保存的結(jié)果不理想埋凯。因此建議在restful接口中繼續(xù)使用原始類型。
文/ThoughtWorks高玉山