簡體   English   中英

如何在 Java 中使用 TimeZone 解決夏令時

[英]How to tackle daylight savings using TimeZone in Java

我必須在我的 Java 應用程序中打印 EST 時間。 我已使用以下方法將時區設置為 EST:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));

但是當在這個時區遵循夏令時時,我的代碼沒有打印正確的時間(它打印的時間少了 1 小時)。

無論是否遵守夏令時,如何使代碼始終讀取正確的時間?

PS:我嘗試將時區設置為 EDT,但並沒有解決問題。

這是開始的問題:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));

應完全避免使用 3 個字母的縮寫,以支持 TZDB 區域 ID。 EST 是東部標准時間 -標准時間從不遵守 DST; 它並不是一個完整的時區名稱。 它是用於部分時區的名稱。 (不幸的是,我沒有遇到過這個“半時區”概念的好詞。)

您需要完整的時區名稱。 例如, America/New_York位於東部時區:

TimeZone zone = TimeZone.getTimeZone("America/New_York");
DateFormat format = DateFormat.getDateTimeInstance();
format.setTimeZone(zone);

System.out.println(format.format(new Date()));

其他答案是正確的,尤其是Jon Skeet 的答案,但已過時。

時間

這些舊的日期時間類已被 Java 8 及更高版本中內置的java.time框架所取代。

如果您只需要 UTC 中的當前時間,請使用Instant類。

Instant now = Instant.now();

EST不是時區,正如Jon Skeet正確答案中所解釋的那樣。 這種 3-4 個字母的代碼既不標准化也不唯一,並且進一步混淆了夏令時 (DST)。 使用“大洲/地區”格式的正確時區名稱。

也許您指的是北美東海岸的東部標准時間? 還是埃及標准時間? 還是歐洲標准時間?

ZoneId zoneId = ZoneId.of( "America/New_York" );
ZoneId zoneId = ZoneId.of( "Africa/Cairo" );
ZoneId zoneId = ZoneId.of( "Europe/Lisbon" );

使用任何此類ZoneId對象將當前時刻調整為特定時區以生成ZonedDateTime對象。

ZonedDateTime zdt = ZonedDateTime.now( zoneId ) ;

通過從第一個對象生成另一個 ZonedDateTime 對象,將該 ZonedDateTime 調整到不同的時區。 java.time 框架使用不可變對象而不是更改(變異)現有對象。

ZonedDateTime zdtGuam = zdt.withZoneSameInstant( ZoneId.of( "Pacific/Guam" ) ) ;

Java 中的日期時間類型表,包括現代的和傳統的。

您可以輸入“EST5EDT”,而不是輸入“EST”作為時區。 正如您所指出的,僅“EDT”不起作用。 這將解釋夏令時問題。 代碼行如下所示:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST5EDT"));

根據這個答案

TimeZone tz = TimeZone.getTimeZone("EST");
boolean inDs = tz.inDaylightTime(new Date());
private static Long DateTimeNowTicks(){
    long TICKS_AT_EPOCH = 621355968000000000L;
    TimeZone timeZone = Calendar.getInstance().getTimeZone();
    int offs = timeZone.getRawOffset();
    if (timeZone.inDaylightTime(new Date()))
        offs += 60 * 60 * 1000;
    return (System.currentTimeMillis() + offs) * 10000 + TICKS_AT_EPOCH;
}
public static float calculateTimeZone(String deviceTimeZone) {
    float ONE_HOUR_MILLIS = 60 * 60 * 1000;

    // Current timezone and date
    TimeZone timeZone = TimeZone.getTimeZone(deviceTimeZone);
    Date nowDate = new Date();
    float offsetFromUtc = timeZone.getOffset(nowDate.getTime()) / ONE_HOUR_MILLIS;

    // Daylight Saving time
    if (timeZone.useDaylightTime()) {
        // DST is used
        // I'm saving this is preferences for later use

        // save the offset value to use it later
        float dstOffset = timeZone.getDSTSavings() / ONE_HOUR_MILLIS;
        // DstOffsetValue = dstOffset
        // I'm saving this is preferences for later use
        // save that now we are in DST mode
        if (timeZone.inDaylightTime(nowDate)) {
            Log.e(Utility.class.getName(), "in Daylight Time");
            return -(ONE_HOUR_MILLIS * dstOffset);
        } else {
            Log.e(Utility.class.getName(), "not in Daylight Time");
            return 0;
        }
    } else
        return 0;
}

在java中,DateFormatter默認使用DST,為了避免夏令時(DST),你需要手動做一個技巧,
首先,您必須獲得 DST 偏移量,即應用了多少毫秒的 DST,例如某處 DST 也是 45 分鍾,而某些地方則是 30 分鍾
但在大多數情況下,夏令時為 1 小時
您必須使用 Timezone 對象並檢查日期是否屬於 DST,然后您必須手動將 DST 的偏移量添加到其中。 例如:

 TimeZone tz = TimeZone.getTimeZone("EST");
 boolean isDST = tz.inDaylightTime(yourDateObj);
 if(isDST){
 int sec= tz.getDSTSavings()/1000;// for no. of seconds
 Calendar cal= Calendar.getInstance();
 cal.setTime(yourDateObj);
 cal.add(Calendar.Seconds,sec);
 System.out.println(cal.getTime());// your Date with DST neglected
  }

實現 TimeZone 類以將時區設置為 Calendar 負責夏令時。

java.util.TimeZone 表示時區偏移量,並計算夏令時。

示例代碼:

TimeZone est_timeZone = TimeZoneIDProvider.getTimeZoneID(TimeZoneID.US_EASTERN).getTimeZone();
Calendar enteredCalendar = Calendar.getInstance();
enteredCalendar.setTimeZone(est_timeZone);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM