Java時區問題


Java時區相關

時間格式

UTC是以原子時計時,更加精准,適應現代社會的精確計時。不過一般使用不需要精確到秒時,視為等同。GMT是前世界標准時,UTC是現世界標准時。每年格林尼治天文台會發調時信息,基於UTC。
GMT和 UTC可以視為幾乎是等同的,UTC更精准,有閏秒的概念。

//世界標准時間UTC,其中T表示時分秒的開始(或者日期與時間的間隔),Z表示這是一個世界標准時間
String utcStr = "2010-10-12T15:24:22Z";
//本地時間,也叫不含時區信息的時間,末尾沒有Z
String localStr = "2010-10-12T15:24:22";
//含有時區的時間,+08:00表示該時間是由世界標准時間加了8個小時得到的,[Asia/Shanghai]表示時區 
String zoneStr = "2017-12-13T09:47:07.153+08:00[Asia/Shanghai]";

表示時間相關的類

表示時間的類主要有個:String、Instant、LocalDateTime、ZonedDateTime,
String是字符串形式的時間,Instant是時間戳,LocalDateTime是不含時區信息的時間,ZonedDateTime是含有時區信息的時間。

LocalDateTime

符合格式的String 可以直接轉換為LocalDateTime

System.out.println(LocalDateTime.parse("2019-12-15 10:10:10", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

LocalDateTime字面意思是本地時間,實際上它可以理解為不含時區信息的時間,只儲存了年月日時分秒,要表達是哪里的時間需要時區解釋。

Instant與ZonedDateTime

Instant是時間戳,是指世界標准時格林威治時間1970年01月01日00時00分00秒(北京時間1970年01月01日08時00分00秒)起至現在的總秒數,Instant本身已經攜帶了時區信息,默認是0時區。
ZonedDateTime是含有時區信息的時間,可以理解為它是Instant的格式化對象,
JDK 8以前的時區是用TimeZone,TimeZone ID是在java里ZoneInfoFile類加載的。在jvm初始化的時候,會讀取jdk安裝目錄下的 ${ java.home } /jre/lib/tzdb.dat,放到其成員變量為zones的ConcurrentHashMap里。當調用TimeZone.getTimeZone(id)方法時,會用id到這個map里進行匹配獲取到指定id的時區。其中TimeZone.getTimeZone("Asia/Shanghai")和TimeZone.getTimeZone("GMT+8")是相同的,可以相互替換使用。

System.out.println(ZonedDateTime.ofInstant(Instant.now(),ZoneId.systemDefault()).toInstant());
System.out.println(ZonedDateTime.ofInstant(Instant.now(),"Australia/Darwin").toInstant());

相同的Instant,在不同的時區有不同的展示時間,所以在用Instant構造ZonedDateTime的時候需要傳入時區;ZonedDateTime可以直接轉化為Instant,並且不同的ZonedDateTime可能會生成同樣的Instant

時區轉換

用戶輸入的String類型的時間是沒有時區信息的,需要人為指定時區再解析。
解析的步驟分2步: 先確定用戶時區
1.把用戶輸入的時間轉化為世界標准時間;//Instant.parse("2010-10-12T15:24:22Z")
2.再把世界標准時間轉為需要的時區的時間。//ZonedDateTime.ofInstant(instant,ZoneId.systemDefault());

不同地區的服務器統一時間的解決方案

首先后端封裝一個接口后獲取服務器相對GMT(格林尼治標准時間)時間的偏移量:

TimeZone zone = TimeZone.getDefault(); 
System.out.println(zone.getRawOffset()); 

這段代碼放在不同時區的服務器上執行結果會不同(前提是服務器的時區設置跟本地時區一致)。如果在泰國執行結果為25200000ms,換算成小時為7,說明泰國的時區的偏移量相對於GMT標准時間相差7小時。下文簡稱“時區偏移量”。

前端首先調用該接口獲取服務器的時區偏移量,再在瀏覽器上獲取本地的時區偏移量,計算出兩個偏移量的差值。本地瀏覽器上獲取當前的時間戳,減去上一步計算出來的差值即可得到服務器這個時間的時間戳,把這個時間戳傳給后端 再轉換成時間,就是服務器對應的時間,存入數據庫即可。
前端:

//服務的時區偏移量,通過接口獲得,注意換成負值 
var serveroffset=-25200000; 
var d = new Date(); 
//獲取本地瀏覽器的時區偏移量 
var localOffset = d.getTimezoneOffset() * 60000; 
//的到本地和偏移量的差值 
var deffoffset=localOffset-(serveroffset); 
//獲取本地瀏覽器時間戳 
var localTime = d.getTime(); 
//計算出傳到服務器的時間戳 
var servertime=localTime+deffoffset; 

通過上述方式,可以實現服務器全球各地部署,系統都可以正常使用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM