2011-08-12 42 views
9

我想將ms-since-1970-timestamp轉換爲帶時區(德國)的日期。奇怪的Java時區日期轉換問題

下面是其工作代碼的兩個變種 - 至少,我記得使用它和它的工作:

import java.text.SimpleDateFormat; 
import java.util.Calendar; 
import java.util.Date; 
import java.util.GregorianCalendar; 
import java.util.Locale; 
import java.util.TimeZone; 

public class TestDate { 

    public static void main(String[] args) { 
     Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("Germany"), Locale.GERMANY); 

     Date d = new Date(); 
     cal.setTime(d); 

     System.out.println(String.format("%02d.%02d.%04d %02d:%02d:%02d", 
       cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.MONTH)+1, cal.get(Calendar.YEAR), 
       cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND))); 

     SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss.S"); 
     df.setTimeZone(TimeZone.getTimeZone("Germany")); 
     System.out.println(df.format(d)); 
    } 

} 

這真的很奇怪,因爲我無法找到2小時的時間差的原因。

它應該是:16:05:20 代碼輸出:14:05:20兩種變體。

有人可以幫我,告訴我這裏出了什麼問題嗎?

+1

+1寫得很好的問題 – andyb

回答

15

這就是問題所在:

TimeZone.getTimeZone("Germany") 

有沒有這樣的時區ID,所以Java在其無窮的智慧決定先不回你不UTC告訴你,什麼是錯誤的。試試這個:

TimeZone.getTimeZone("Europe/Berlin") 

維基百科有一個list of IANA time zone IDs,但它有點過時(在寫作的時間); IANA data是最新的,但它不容易瀏覽...

-2

日期對象沒有時區。

Date d = new Date(); // here you have you current time - at that moment it was 16:05:20 

這是你的機器上的時間,當您使用的SimpleDateFormat並設置時區,然後你顯示UTC時間有UTC + 2。

+0

正如你所說的,日期不具有時區 - 這是* *總是在UTC值,所以在那一刻,它代表UTC 14:05。使用SimpleDateFormat並設置時區根據給定的時區顯示* local *時間 - 但不幸的是「德國」的時區實際上並不存在,所以它默認爲UTC。使用*工作*時區將顯示正確的本地時間。 –

1

我相信問題是您所運行平臺上的默認時區。

java.util.Date()確實有一個時區。它維護着「繼承的」時區信息,它似乎是從系統的默認語言環境獲取的。

此代碼。

TimeZone tz = TimeZone.getTimeZone("GMT-03:00"); 
Calendar cal = Calendar.getInstance(tz); 
cal.set(1953, 2, 22, 4, 20, 13); 
Date dateTime = cal.getTime(); 
System.out.println(dateTime.toString()); 

得到這個我的系統,這是使用PST語言環境:週六03月21日23點20分一十三秒PST 1953年

我不相信有使用java.util.Date object的方式,或使用它的DateFormat對象來精確處理來自「外部」時區的時間信息。

+0

語言環境的提及不正確。區域設置與時區無關。語言環境會影響日期和月份名稱等語言以及用於生成日期 - 時間值文本表示的默認格式。例如,您可以在印度的一個時區使用魁北克的地區('Locale.CANADA_FRENCH')。 –

0

Answer by Jon Skeet是正確的,您使用了不正確的時區名稱。

java.time

下面是使用現代java.time類,取代已被證明是如此麻煩和混亂的舊的遺留日期時間類的解決方案。

Instant instant = Instant.ofEpochMilli(milliseconds_since_1970); // Or Instant.now() for current moment. 
ZoneId z = ZoneId.of("Europe/Berlin"); 
ZonedDateTime zdt = instant.atZone(z); 

生成一個本地化的字符串來表示該日期時間值。

Locale l = Locale.GERMANY; // Or Locale.CANADA_FRENCH, etc. 
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(l); 
String output = zdt.format(f);