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;
通過上述方式,可以實現服務器全球各地部署,系統都可以正常使用。