Java中如何顯示不同時區的時間(原理詳解)

2020-11-27 電子發燒友

Java中如何顯示不同時區的時間(原理詳解)

電子發燒友網 發表於 2019-01-01 14:58:00

在Java中,如何獲取不同時區的當前時間?

你知道這道題的正確答案應該如何回答嗎?背後的原理又是什麼呢?

然後,緊接著,我又提出了以下問題:

為什麼以下代碼無法得到美國時間。(在東八區的計算機上)

System.out.println(Calendar.getInstance(TimeZone.getTimeZone(「America/Los_Angeles」)).getTime());

接下來,本文就圍繞這兩個問題,來帶領讀者一起學習一下哪些和Java中的時間有關的概念。

時區

前面提到了時區,可能很多讀者不知道什麼是時區,先來簡單介紹一下。

時區是地球上的區域使用同一個時間定義。以前,人們通過觀察太陽的位置(時角)決定時間,這就使得不同經度的地方的時間有所不同(地方時)。1863年,首次使用時區的概念。時區通過設立一個區域的標準時間部分地解決了這個問題。

世界各個國家位於地球不同位置上,因此不同國家,特別是東西跨度大的國家日出、日落時間必定有所偏差。這些偏差就是所謂的時差。

為了照顧到各地區的使用方便,又使其他地方的人容易將本地的時間換算到別的地方時間上去。有關國際會議決定將地球表面按經線從東到西,劃成一個個區域,並且規定相鄰區域的時間相差1小時。在同一區域內的東端和西端的人看到太陽升起的時間最多相差不過1小時。當人們跨過一個區域,就將自己的時鐘校正1小時(向西減1小時,向東加1小時),跨過幾個區域就加或減幾小時。這樣使用起來就很方便。

世界時區

現今全球共分為24個時區。由於實用上常常1個國家,或1個省份同時跨著2個或更多時區,為了照顧到行政上的方便,常將1個國家或1個省份劃在一起。所以時區並不嚴格按南北直線來劃分,而是按自然條件來劃分。例如,中國幅員寬廣,差不多跨5個時區,但為了使用方便簡單,實際上在只用東八時區的標準時即北京時間為準。

格林威治時間

前面提到了,時區通過設立一個區域的標準時間部分地解決了不同地方看到的太陽位置不一樣而無法定義時間的問題。那麼這個標準時間是什麼呢?

前面還提到。中國位於東八區,一般是用GMT+8來表示東八區這個時區。那麼,看起來GMT就是這個所謂的標準時間。GMT是個什麼東西呢?為什麼要在他的基礎上+8來表示東八區呢?

GMT,是Greenwich Mean Time的縮寫,及格林尼治(格林威治)平時,是指位於英國倫敦郊區的皇家格林尼治天文臺當地的平太陽時,因為本初子午線被定義為通過那裡的經線。

格林威治子午線

自1924年2月5日開始,格林尼治天文臺負責每隔一小時向全世界發放調時信息。國際天文學聯合會於1928年決定,將由格林威治平子夜起算的平太陽時作為世界時,也就是通常所說的格林威治時間

一般使用GMT+8表示中國的時間,是因為中國位於東八區,時間上比格林威治時間快8個小時。

北京時間還可以用CST表示,即China Standard Time,又名中國標準時間,是中國的標準時間。當格林威治時間為凌晨0:00時,中國標準時間正好為上午8:00。

所以,有等式:CST=GMT +8 小時

時間戳

前面提到了全世界各個時區的時間可能都是不一樣的,那麼有沒有一個什麼樣的辦法可以不受時區的限制,可以精確的表示時間呢。

其實是有的,這個方法就是時間戳。

時間戳(timestamp),一個能表示一份數據在某個特定時間之前已經存在的、 完整的、 可驗證的數據,通常是一個字符序列,唯一地標識某一刻的時間。

時間戳是指格林威治時間1970年01月01日00時00分00秒起至現在的總秒數。

有了時間戳,無論我們深處哪個時區,從格林威治時間1970年01月01日00時00分00秒到現在這一時刻的總秒數應該是一樣的。所以說,時間戳是一份能夠表示一份數據在一個特定時間點已經存在的完整的可驗證的數據。

1970-01-01

不知道大家有沒有注意到一個比較特殊的時間,1970-01-01,相信每一個開發者對這個時間都並不陌生。一般如果軟體系統中出現這個時間的時候,代表著出現了網絡故障、線上bug等。

微信手機充值Bug

當有些計算機存儲或者傳輸時間戳出錯時,這個時間戳就會取默認值。而在計算機中,默認值通常是 0。

當 Timestamp 為 0,就表示時間(GMT)1970年1月1日0時0分0秒。中國使用北京時間,處於東 8 區,相應就是早上 8 點。因此在中國這邊,時間出錯了,就經常會顯示成 1970年1月1日 08:00。

System.out.println(new Date(0)); //Thu Jan 01 08:00:00 CST 1970

當我們在Java代碼中使用new Date(0)來創建時間的時候,得到的結果就是Thu Jan 01 08:00:00 CST 1970,既1970年1月1日 上午08點整。

Date

前面提到了java.util.Java中的Date類,這個類通常用來表示時間。你可以通過getTime()方法訪問java.util.Date實例的日期和時間,比如像這樣:

Date date = new Date(); long time = date.getTime();

以上代碼,其實得到的就是時間戳,在源碼中也有明確的表述:

所以,我們就可以認為java.util.Java其實表示的就是從格林威治1970年1月1日零點到現在這一時刻的總秒數。

從Date的源碼中也可以看到,Date中是不包含時區有關的信息的,因為時間戳和時區沒有關係。

那麼,如果想要把一個時間戳轉換成不同時區的時間輸出應該怎麼做呢?

顯示不同時區的時間

想要把時間戳轉換成對應時區的時間,總要有個地方可以獲取時區吧。其實,我們的計算機中是有時區相關的信息的。

無論我們使用的是哪種作業系統的電腦,都是可以查看時間的,而一般情況下,我們拿到的電腦都會展示中國時間,那是因為作業系統中已經設置了一個默認時區。

其實,Java中的時區信息也是從作業系統中取到的,默認情況下會使用作業系統的時區。

當我們使用System.out.println來輸出一個時間的時候,他會調用Date類的toString方法,而該方法會讀取作業系統的默認時區來進行時間的轉換。

主要代碼如上。也就是說如果我們想要通過System.out.println輸出一個Date類的時候,輸出美國洛杉磯時間的話,就需要想辦法把defaultTimeZone改為America/Los_Angeles,這個方法就是:

TimeZone.setDefault(TimeZone.getTimeZone(「America/Los_Angeles」));

所以,當我們想要輸出美國洛杉磯時間時,可以選擇這種方式:

TimeZone.setDefault(TimeZone.getTimeZone(「America/Los_Angeles」)); Date date =new Date();System.out.println(date);

還有一種方式,就是通過SimpleDateFormat來處理,這種方式我們在為什麼阿里巴巴禁止把SimpleDateFormat定義為static類型的中也介紹過。這裡就不再展開了。

接下來,我們再回到文章開始的那個問題:

為什麼以下代碼無法得到美國時間。(在東八區的計算機上)

System.out.println(Calendar.getInstance(TimeZone.getTimeZone(「America/Los_Angeles」)).getTime());

其實答案前面也已經說過了,我們通過查看Date.toString的源碼,發現在輸出的過程中該方法只會去獲取系統的默認時區,只有修改了默認時區才會顯示該時區的時間。

但是,通過閱讀Calendar的源碼,我們可以發現,getInstance方法雖然有一個參數可以傳入時區,但是並沒有將默認時區設置成傳入的時區。

而在Calendar.getInstance.getTime後得到的時間只是一個時間戳,其中未保留任何和時區有關的信息,所以,在輸出時,還是顯示的是當前系統默認時區的時間。

Java 8與時區

了解Java8 的朋友可能都知道,Java8提供了一套新的時間處理API,這套API比以前的時間處理API要友好的多。

Java8 中加入了對時區的支持,帶時區的時間為分別為:ZonedDate、ZonedTime、ZonedDateTime。其中每個時區都對應著 ID,地區ID都為 「{區域}/{城市}」的格式,如Asia/Shanghai、America/Los_Angeles等。

在Java8中,直接使用以下代碼即可輸出美國洛杉磯的時間:

總結

世界上有很多時區,不同的時區的時間不一樣,中國使用東八區的時間作為標準時間。美國自東海岸至西海岸橫跨西五區至西十區,共六個時區。

所謂東八區,一般表示成GMT+8,這裡的GMT指的是格林威治時間。計算機中經常使用時間戳來表示時間,時間戳指的就是當前時間舉例格林威治的1970-01-01 00:00:00的總秒數。

而Java中的Date類中是不包含時區信息的,在使用System.out.println列印Date的時候,回調用Date.toString方法,該方法會獲取系統的默認時區來轉換時間。

在Java8中可以使用ZonedTime、ZonedDate和ZonedDateTime來表示帶有時區信息的時間。

LocalDateTime now = LocalDateTime.now(ZoneId.of(「America/Los_Angeles」)); System.out.println(now);

打開APP閱讀更多精彩內容

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容圖片侵權或者其他問題,請聯繫本站作侵刪。 侵權投訴

相關焦點

  • 「第6節」java中如何顯示當前時間
    大家好,今天我們學習下java編程中如何讓程序顯示當前的時間。請看下面的具體例子,我來逐步分析。GMT(格林威治標準時間),GMT標準格式是:小時:分鐘:秒。該範例使用了一個方法currentTimeMillis(),返回的數值是當前時間與1970年1月1日0點之間的毫秒數差值,所以,它是一個總的毫秒數。1、程序中,totalSeconds= totalMilliseconds/1000,得到的是總的秒數(1秒=1000毫秒)。
  • 如何在Windows 10中設置多時區時鐘
    當你需要與全球各地的人協同工作,與處於全球不同時區的家人或朋友打交到時,Windows 系統中的多時區時鐘功能便會派上用場。
  • 俠說java8-LocalDateTime等時間使用手冊(全),先mark後看
    前言java8的時間日期api給我們提供了極大的便利。如何更好的熟悉使用時間api也是學習java8的一個很重要的知識點,下面我們一起來學習學習。本篇文章代碼比較多,可以作為工具,需要使用時,再來查閱。目錄1.普通Date時間如何轉為LocalDateTime?
  • php 中關於時區的那點事
    科普一下什麼是時區眾所周知,地球繞著太陽轉的同時也會自轉,因此同一時刻不同地區所接收到太陽照射的情況不同,所以有的地區是日出,有的地區是日落,還有的地區可能是黑夜.既然地球上的不同地區時間不同,那總要有統一的時間刻度才能方便文化科技交流吧,不然大家說的都是當地時間,這樣豈不是亂套了?
  • 聽乾貨君聊項目多時區處理
    聽乾貨君聊項目多時區處理 很多時候在項目的開發中或許沒有接觸過多時區,項目大多是部署國內,同時僅僅為國內用戶提供服務,一旦當用戶到國外後,項目中的很多時間都變得與當地時間不一樣,對用戶非常不友好。
  • Java研發技術——Volatile原理詳解
    這裡說的數據依賴性僅針對單個處理器中執行的指令序列和單個線程中執行的操作,不同處理器之間和不同線程之間的數據依賴性不會被考慮,也就是說多線程下重排序可能會影響執行的結果。,java通過屏蔽這些差異,統一由jvm來生成內存屏障的指令。
  • 搞清日期、時間與時區
    理論上來說,格林尼治標準時間的正午是指當太陽橫穿格林尼治子午線時的時間。但由於地球在它的橢圓軌道裡的運動速度不均勻,這個時刻可能和實際的太陽時相差16分鐘。由於地球每天的自轉是有些不規則的,而且正在緩慢減速。所以,格林尼治時間已經不再被作為標準時間使用。現在的標準時間(UTC)由原子鐘提供。
  • Java類隔離加載實現原理是什麼?
    到了運行的時候,默認情況下一個項目的所有類都是用同一個類加載器加載的,所以不管你依賴了多少個版本的 C,最終只會有一個版本的 C 被加載到 JVM 中。當 B 要去訪問 Log.error,就會發現 Log 壓根就沒有 error 方法,然後就拋異常java.lang.NoSuchMethodError。這就是類衝突的一個典型案例。
  • Globalization Design: 理解時區
    我猜測,我們多數開發或者PM會自認為這些都很簡單,但實際上還是在不斷出現不那麼global的問題,而且這些小問題往往還都在我們的認知盲區中。所以接下來,我們不妨花幾分鐘時間來討論下時區相關的概念。https://en.wikipedia.org/wiki/Time_zone簡而言之,為了滿足法律、商業和社交需求,我們用時區將全球劃分成不同地區並遵循統一的時間表達方法。剛才說到的GMT是零時區的一個縮寫(也叫Z - Zulu Time Zone),還有CST(China Standard Time)也是一個時區的縮寫,全球各個國家、地區或城市根據時區的劃分使用特定的縮寫。
  • Java反射機制深入詳解
    反射是java語言的一個特性,它允程序在運行時(注意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許一個java的類獲取他所有的成員變量和方法並且顯示出來。Java 的這一能力在實際應用中也許用得不是很多,但是在其它的程序設計語言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒有辦法在程序中獲得函數定義相關的信息。
  • Java中Lambda表達式的5種不同語法
    1.標準語法考慮以下示例:String[] arr = {"program", "creek", "is", "a", "java", "site"};Arrays.sort如果可以從上下文中推斷出參數的參數類型,則可以省略該類型。
  • 裸眼3D立體顯示技術原理詳解
    引言  眾所周知,現實世界是一個三維空間,除去時間這一維度,現實世界是由長度、寬度和高度三個維度組成,我們每天就生活在這個三維世界中,而現有的顯示設備大多數都只能顯示二維信息,並不能帶給人真實的三維感覺。
  • 蕭邦盛邀遨遊環球:L.U.C Time Traveler One世界時間腕錶與GMT One 兩地時區腕錶
    氣勢出眾的L.U.C Time Traveler One腕錶是L.U.C系列的首枚世界時間腕錶,是環球旅人最便捷實用的腕上儀表。而L.U.C系列GMT One雙時區腕錶搭載融入GMT功能的嶄新L.U.C 01.10-L機芯,精巧提供第二時區顯示功能。
  • 詳解Java表達式與運算符
    在java語言中,運算符可分為5種類型:算術運算符、賦值運算符、關係運算符、邏輯運算符、位運算符。根據操作數的不同,運算符又分為單目運算符、雙目運算符和三目運算符。單目運算符只有一個操作數,雙目運算符有兩個操作數,三目運算符則有三個操作數。
  • Linux - 時區和時間調整方法
    前言全球不同的地方有不同的時區劃分,所有了以全球標準時間(UTC)和本地時間(localtime)區別。一般我們都設置成本地時間,方便操作與統計。機器裡有兩個時鐘,硬體時鐘從根本上講是CMOS時鐘,而系統時鐘是由內核維護的。
  • 深入分析java中的多態(從jvm角度分析)
    對於java中多態概念的理解一直是面試常問的問題,所以今天花了一些時間好好地整理了一下,力求從java虛擬機的角度來分析和理解多態。一、認識多態1、方法調用在Java中,方法調用有兩類,動態方法調用與靜態方法調用。
  • 如何調整時區圖?
    如何調整時區圖?
  • 大廠如何使用Java8日期時間?
    顯示兩個不同時間,說明時區發生作用。這裡有兩種3.2 如何正確保存日期時間保存的時間無時區屬性,不涉及時區時間差問題的世界統一時間。常說的時間戳或Java中的Date類就是這種方式,也是推薦方案比如年/月/日 時:分:秒,務必同時保存時區信息。有了時區,才能知道該字面量時間真正的時間點,否則它只是一個給人看的時間表示且只在當前時區有意義。
  • Java中加載資料庫驅動的方式有幾種?背後的原理是什麼?
    Driver接口先來了解下java.sql.Driver接口,java.sql.Driver是所有JDBC驅動程序需要實現的接口。這個接口是提供給資料庫廠商使用的,不同廠商實現該接口的類名是不同的,例如MySQL 8.x的JDBC驅動的類名是:com.mysql.cj.jdbc.Driver。
  • 如何使用JAVA反射/JAVA反射實例
    JAVA反射技術,在平時我們的開發中雖然很少會用到例如讀取配製文件可能就用到這個技術,但在我們所使用的框架源碼中是經常會用到的。> c3 = null ;  // 指定泛型  try{   // 以下的操作形式是在開發中最常用的一種形式   c1 = Class.forName("com.test.instancedemo.X") ;  }catch(ClassNotFoundException e){   e.printStackTrace() ;  }  c2 = new X().getClass() ;  //