【问题标题】:Day Light Saving Issue with Java CalendarJava 日历的夏令时问题
【发布时间】:2018-08-19 14:06:31
【问题描述】:

这是关于 Java 日历以及我们在多伦多今天夏令时后遇到的影响。

下面是代码

    Date date = new Date(); //Sun Mar 11 00:00:00 EST 2018
    Integer time = 349;

    Calendar scheduleDateCal = Calendar.getInstance();
    scheduleDateCal.setTime(date);

    scheduleDateCal.set(Calendar.MINUTE, 0);
    scheduleDateCal.set(Calendar.HOUR_OF_DAY, 0);
    String strSchAdminTime = String.valueOf(time);
    Integer schAdminMinute = time;

    if (strSchAdminTime.length() >= 2) {
        schAdminMinute = Integer.valueOf(strSchAdminTime.substring(strSchAdminTime.length()-2));
    } 
    if(time>60){
        Integer schAdminHour = Integer.valueOf(strSchAdminTime.substring(0,strSchAdminTime.length()-2));
        scheduleDateCal.add(Calendar.HOUR_OF_DAY, schAdminHour);
    }else{
        scheduleDateCal.add(Calendar.HOUR_OF_DAY, 0);
    }
    scheduleDateCal.add(Calendar.MINUTE, schAdminMinute);

    System.out.println(scheduleDateCal.getTime());

我知道这段代码没有采用最佳实践,但是我需要在当前版本中维护它。在这里它使用整数来表示时间部分,然后有一个逻辑可以从中提取小时和分钟。

当我遵循逻辑时,小时部分是 3。然后有一个逻辑将此时间添加到日历对象,其值为 'Sun Mar 11 00:00:00 EST 2018' 并带有以下语句

scheduleDateCal.add(Calendar.HOUR_OF_DAY, schAdminHour);

理论上,经过此计算,日历对象的值应为“Sun Mar 11 03:00:00 EDT 2018”。但是它返回“Sun Mar 11 04:00:00 EDT 2018”我知道从今天开始,夏令时时间将提前一小时。任何人都可以帮助我理解这一点

感谢您的帮助。

【问题讨论】:

标签: java dst java.util.date java.util.calendar


【解决方案1】:

今天 00:00:00(2018 年 3 月 11 日星期日)夏令时 (DST) 尚未生效,因此该时间正确呈现为 Sun Mar 11 00:00:00 EST 2018(东部标准的东部标准时间时间)。 Date.toString 根据 Date 对象中包含的时间在 EST 和 EDT 之间进行选择(而不是根据调用 toString 方法的时间)。当您将该时间添加 3 小时时,您会在 2 点越过时间,此时时钟已调快到 3 点。因此,在您开始时间 3 小时后,时间是美国东部时间 04:00:00(美国东部夏令时间)。

PS 现代代码

PS 如果您或其他人有兴趣,这里是您的代码的现代版本——既简单又短。将时间设置为 03:49:

    int time = 349;
    ZoneId zone = ZoneId.of("America/Toronto");
    ZonedDateTime scheduledDateTime = LocalDate.now(zone)
            .atTime(time / 100, time % 100)
            .atZone(zone);
    System.out.println(scheduledDateTime);

今天打印出来了

2018-03-11T03:49-04:00[美国/多伦多]

当然更好的是,如果您可以完全摆脱将 03:49 表示为整数值 349。要使用 JVM 的时区设置,您可以将 zone 设置为 ZoneId.systemDefault()。这是脆弱的,因为您的程序的其他部分或在同一 JVM 中运行的其他程序可能随时更改该设置。

将时间设置为午夜后 3 小时 49 分钟(正如您所见,与 DST 转换不同):

    ZonedDateTime scheduledDateTime = LocalDate.now(zone)
            .atStartOfDay(zone)
            .plusHours(time / 100)
            .plusMinutes(time % 100);

这次我得到了

2018-03-11T04:49-04:00[美国/多伦多]

【讨论】:

  • 感谢@Ole V.V 的评论。当我调试代码时,我发现日历对象最初是 EDT,但一旦它执行 scheduleDateCal.set(Calendar.HOUR_OF_DAY, 0);它更改为 est
  • 听起来不错。 Calendar 对象的初始值是当前时间,所以如果你在 3 之后运行代码,它会在 EST 中。
【解决方案2】:

EST 是 -5,EDT 是 -4,所以当你调用 add() 时你会得到 1 小时。 如果您需要不同时区的结果,您可以使用scheduleDateCal.set(Calendar.HOUR_OF_DAY, schAdminHour)scheduleDateCal.set(Calendar.MINUTE, schAdminMinute)

【讨论】:

  • 感谢您的回复。你知道为什么 Date date = new Date();在 EST(2018 年 3 月 11 日星期日 00:00:00 EST)重新运行,即使我的时区更改为 EDT
  • 你的java版本是新的吗?当地方当局更改夏令时开始/结束规则时,有时需要更新 java 运行时中包含的时区数据库。您可以使用 Timezone Updater Tool 修补您的 java,请参阅链接:oracle.com/us/technologies/java/tzupdater-readme-136440.html
猜你喜欢
  • 2018-08-27
  • 1970-01-01
  • 2012-11-16
  • 2023-04-05
  • 1970-01-01
  • 2010-09-27
  • 2012-09-06
  • 2013-05-16
  • 1970-01-01
相关资源
最近更新 更多