如何在没有 Joda Time 的情况下在 Java 7 中正确处理夏令时?

Posted

技术标签:

【中文标题】如何在没有 Joda Time 的情况下在 Java 7 中正确处理夏令时?【英文标题】:How to handle daylight saving time properly in Java 7 without Joda Time? 【发布时间】:2016-02-01 14:57:42 【问题描述】:

在将其标记为重复之前,请仔细阅读,另外不能使用 Joda Time 和 Java 8 time.util*

我正在尝试获取启用 DST 的国家/地区的当前日期。由于使用时区,它会得到[local-millis] = [UTC-millis] + [offset-millis],所以我添加了DST_OFFSET 以获取启用夏令时的国家/地区的时间,就像在Linux 机器上所做的那样GMT_TIME + LOCAL_TIME_ZONE_OFFSET + DST_OFFSET 获取当前本地时间。

打印Istanbul 的当前时间的代码,该时间当前已启用 DST 1 小时。

public class DstInstanbul 

    public static void main(String...args)

        Calendar calendar = Calendar.getInstance();

        TimeZone timeZone = TimeZone.getTimeZone("Europe/Istanbul");

        calendar.setTimeZone(timeZone);

        calendar.add(Calendar.MILLISECOND, timeZone.getDSTSavings());


        SimpleDateFormat simpleDateFormatLocal = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        simpleDateFormatLocal.setTimeZone(TimeZone.getTimeZone("Europe/Istanbul"));

        System.out.println("Current date and time : " + simpleDateFormatLocal.format(calendar.getTime()));


       System.out.println("Current date and time : " + simpleDateFormatLocal.format(calendar.getTime()));
       System.out.println("The TimeZone is : " + calendar.getTimeZone().getID());

    

这给了我正确的输出

Current date and time : 2015-11-01 20:49:54
The Hour of the Day is : 20
The TimeZone is : Europe/Istanbul

但是由于上面的代码不是通用的,所以我尝试添加以下行,这样如果只启用日光,那么只需添加 dstSaving 所以我用

更改了以下calendar.add(Calendar.MILLISECOND, timeZone.getDSTSavings());
if (timeZone.inDaylightTime(new Date()))
            calendar.add(Calendar.MILLISECOND, timeZone.getDSTSavings());
       

但问题是,如果我这样做,我会得到没有任何 DST 的输出。和打印System.out.println(timeZone.inDaylightTime(new Date())); 给了我错误的结果,但是夏令时在那里,你可以在这个链接中看到Istanbul clock

Current date and time : 2015-11-01 19:54:49
The TimeZone is : Europe/Istanbul.

Brazil 时区的相同逻辑在 inDaylightTime 中给出了正确的结果,但现在提前一小时显示结果

以讨论的方式排序的所有代码的 Ideone 链接 1.https://ideone.com/4NR5Ym 2.https://ideone.com/xH7vhp 3.https://ideone.com/tQenb5

我的问题是timeZone.inDaylightTime(new Date()) 与伊斯坦布尔时区有什么问题。为什么显示为假。为什么对于巴西,即使inDaylightTime 为真,我也没有得到当前的 DST 时间。 处理这种情况的正确方法是什么?

【问题讨论】:

【参考方案1】:

你不应该这样做:

calendar.add(Calendar.MILLISECOND, timeZone.getDSTSavings());

你也不应该这样做:

if (timeZone.inDaylightTime(new Date()))
    calendar.add(Calendar.MILLISECOND, timeZone.getDSTSavings());

您无需手动调整时间。它会根据您格式化的日期自动为您完成。调用 add 只会移动您正在使用的瞬时时间点。

删除这些行,并更新您的 JVM 以接受最新的土耳其 DST 更改(如 Monz 在他的回答中所述),您应该一切顺利。

【讨论】:

正确,直接操作日历值来调整夏令时是不正确的。更改日历对象的时间值实际上是更改事件发生的时间(或日历值要表示的任何内容。)时间 zone 更改调整时间的 显示 值(即为什么完全格式化的时间字符串总是包含时间偏移量。)这是我今天写的一篇文章:monztech.com/index.php/2015/11/01/…【参考方案2】:

今天土耳其的时区和夏令时似乎存在一些问题。

这可能是因为Turkey has changed the date for the daylight savings switch from November 1 to November 8.

您的 JVM 中的时区数据可能不是最新的。 Oracle has an update for their JVM.

您从上面的链接下载的时区数据更新程序是一个可执行的 jar 文件。在 Unix 主机上更新 JVM:

sudo java -jar tzupdater.jar --update --location http://www.iana.org/time-zones/repository/tzdata-latest.tar.gz

该工具似乎没有在更新时输出任何内容,因此要验证运行:

java -jar tzupdater.jar --version 

土耳其更新的时区数据版本为tzdata2015g

【讨论】:

好的.. 但是对于没有那个 calendar.add 的巴西,我得到正确的输出意味着不需要添加 dst 你能建议为什么吗? 无法在 Windows 中执行此操作!即使GitBash 我也有例外:Caused by: java.io.EOFException at java.util.zip.GZIPInputStream.readUByte(GZIPInputStream.java:268)

以上是关于如何在没有 Joda Time 的情况下在 Java 7 中正确处理夏令时?的主要内容,如果未能解决你的问题,请参考以下文章

为什么org.joda.time.LocalDate是没有时区的日期?

Joda-Time 中两个日期之间的天数

使用 Joda Time 时无法生成启用 proguard 的签名 APK

joda-time

java.lang.ClassNotFoundException: org.joda.time.ReadablePeriod

如何在 Joda Time 中检测模糊的 DST 重叠?