世界時區和Java時區詳解

0、引言

Druid中時區的問題一直困擾着咱們,因此我專門去研究了一下世界時區和Java中的時區,對使用Druid很用幫助.java

一、UTC時間&GMT時間

UTC時間是時間標準時間(Universal Time Coordinated),UTC是根據原子鐘來計算時間,偏差很是小。安全

UTC也是指零時區的時間,若是要表示其餘時區的時間,這裏要注意沒有UTC+0800或者UTC+8這樣的表示方式(至少Java裏面沒有,通常用於口頭表示),只有Asia/Shanghai這樣的表示方式,詳細的時區列表參考這個文檔時區列表,不要問我爲何沒有北京時區。。。測試

GMT時間是根據地球的自轉和公轉來計算時間,老的時間計量標準,這裏咱們不過多討論ui

二、表達時間方式

咱們通常表示時間都會帶格式以方便理解,例如時間表達式是'2018-09-12 08:00:00',由於咱們在東八區,因此默認是:北京時間2018年9月12號8點整。可是若是是一個美國人看到這個時間,就會認爲是美國東部or西部時間的2018年9月12號8點整。因此從這種表達方式很不許確,由於沒有指明究竟是哪一個時區的時間!!!!線程

因此準確的表達時間必須帶有時區,例如2018-09-12 08:00:00+0800,表達了Asia/Shanghai這個時區的時間2018年9月12號8點整。這裏要注意+0800並非表示加8小時的意思,只是表示這個時間'2018-09-12 08:00:00'是東八區Asia/Shanghai的時間,僅此而已。code

三、UTC時間的時間戳

講清楚了時間表達方式,再講時間戳。其實時間戳是沒有時區概念的,或者說時間戳只能是0時區的。時間戳是從1970-01-11 00:00:00+0000開始的(緣由你們都知道),也就是在'1970-01-11 00:00:00+0000'這個時間點,時間戳是0。再換句話說在'1970-01-11 08:00:00+0800'時間戳也是0。這也是Java裏時間組件的默認方式,無論用戶輸入的人類可識別的時間是什麼格式,在內部統一存的是時間戳。orm

例如時間是'2018-09-01 08:00:00+0800',那麼使用date.getTime()獲取到時間戳是1535760000000;時間是'2018-09-01 00:00:00+0000',獲取到時間戳也是1535760000000。文檔

測試代碼以下:get

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
System.out.println(sdf.parse("2018-09-01 08:00:00+0800").getTime());
System.out.println(sdf.parse("2018-09-01 00:00:00+0000").getTime());

能夠觀察到這2行代碼的輸出都是1535760000000,這就證實了上面的觀點。再囉嗦2點:it

  • 第一行代碼DateFormat中Z表示時區,因此String類型格式時間帶上+0800這種表達式,就能正確獲取時間戳了。

  • SimpleDateFormat是線程不安全的,不要用

四、時區設置

爲何咱們寫如下代碼的時候,程序能正確知道咱們的時區呢?

SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf2.parse("2018-09-01 08:00:00").getTime());

由於咱們在mac上設置了時區

在Java中也能夠設置時區

1)啓動設置
java -Duser.timezone=Asia/Shanghai -jar xxx.jar

2) 代碼中設置

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.parse("2018-09-01 08:00:00").getTime());

3) 單次處理生效,建議使用joda的時間包

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.9.9</version>
</dependency>

DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").withChronology(ISOChronology.getInstance(DateTimeZone.forID("Asia/Shanghai")));
System.out.println(dateTimeFormatter.parseDateTime("2018-09-01 08:00:00").getMillis());
相關文章
相關標籤/搜索