Joda-Time,夏令时更改和日期时间解析

Fil*_*sso 6 java parsing jodatime dst

我有以下问题使用Joda-Time解析和生成夏令时(DST)小时的日期和时间.这是一个例子(请注意,2008年3月30日是意大利的夏令时变化):

DateTimeFormatter dtf = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss");
DateTime x = dtf.parseDateTime("30/03/2008 03:00:00");
int h = x.getHourOfDay();
System.out.println(h);
System.out.println(x.toString("dd/MM/yyyy HH:mm:ss"));
DateTime y = x.toDateMidnight().toDateTime().plusHours(h);
System.out.println(y.getHourOfDay());
System.out.println(y.toString("dd/MM/yyyy HH:mm:ss"));
Run Code Online (Sandbox Code Playgroud)

我得到以下输出:

3
30/03/2008 03:00:00
4
30/03/2008 04:00:00
Run Code Online (Sandbox Code Playgroud)

当我解析小时时,我得到小时为3.在我的数据结构中,我保存了存储午夜时间的那一天,然后我在一天中的每个小时(0-23)有一些值.然后,当我写出日期时,我会重新计算午夜加上小时的完整日期时间.当我总结3个小时到我的午夜时,我得到04:00:00!如果我再次解析它,我会得到4小时!

我的错误在哪里?有什么方法可以在我解析时获得第2小时或在打印时获得第3小时?

我也尝试手工构建输出:

String.format("%s %02d:00:00", date.toString("dd/MM/yyyy"), h);
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,小时2,我生成30/03/2008 02:00:00,这不是一个有效的日期(因为小时2不存在),不能再解析了.

预先感谢您的帮助.菲利波

Paw*_*yda 5

当我总结3个小时到我的午夜时,我得到04:00:00!如果我再次解析它,我会得到4小时!我的错误在哪里?

您已经提到过这个日期恰好是时间的变化.所以没有错.2010年3月30日00:00 CEST(意大利的时区)正好是2010年3月29日23:00 UTC.当您添加3小时后,您将获得2010年3月30日02:00 UTC.但是这是我们切换时间(发生在01:00 UTC)的时刻,因此当你将时间转换为当地时区时,你会得到3月30日04:00.这是正确的行为.

有什么方法可以在我解析时获得第2小时或在打印时获得第3小时?

不,因为2010年3月30日02:00 CEST 不存在.正好在2010年3月30日01:00 UTC我们将时间从+1小时切换到+2小时与UTC相比,因此2010年3月30日00:59 UTC是2010年3月30日:01:59 CEST,但2010年3月30日01 :00 UTC成为2010年3月30日03:00 CEST.No 02:在该特定日期存在xx小时.

BTW.在一个星期内,你可以期待另一个"有趣".你能告诉UTC这个日期是指:

2010年10月31日02:15 CEST?

嗯,有趣的是,我们不知道.它可能是2010年10月31日00:15 UTC(实际时间切换之前)或2010年10月31日01:15 UTC(切换之后).

这就是为什么你应该总是存储与UTC相关的日期和时间,并在显示之前将它们转换为本地时区,否则你可能会有歧义.

HTH.


Knu*_*ubo 4

对于夏令时的日子,您保存数据的数据结构并不是非常理想。你这一天的时间应该只有 23 个小时。

如果你这样做:

    DateTimeFormatter dtf = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss").withLocale(Locale.US);
    DateTime x = dtf.parseDateTime("30/03/2008 00:00:00");

    DateTimeFormatter parser = DateTimeFormat.fullDateTime();
    System.out.println("Start:"+parser.print(x));

    DateTime y = x.plusHours(4);

    System.out.println("After add of 4:"+parser.print(y));
Run Code Online (Sandbox Code Playgroud)

您得到了预期结果,即时间为 05:00。

我建议您改变存储日期和使用日期的方式。如果不是,则在存储一天中的小时时必须处理夏令时。

你可能会这样做:在我们将时间向前移动一小时的情况下,在这种情况下,你必须存储 4 而不是 5 作为 5 的时间。当你计算时间时,你应该使用 plusHours()方法来获取实际时间。我想你可能会逃脱类似的惩罚:

public class DateTest {
    private static final int HOUR_TO_TEST = 2;

  public static void main(String[] args) {
    DateTimeFormatter dtf = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss");
    DateTime startOfDay = dtf.parseDateTime("30/03/2008 00:00:00");

    /* Obtained from new DateTime() in code in practice */
    DateTime actualTimeWhenStoring = startOfDay.plusHours(HOUR_TO_TEST);

    int hourOfDay = actualTimeWhenStoring.getHourOfDay();
    int hourOffset = startOfDay.plusHours(hourOfDay).getHourOfDay();

    System.out.println("Hour of day:" + hourOfDay);
    System.out.println("Offset hour:" + hourOffset);

    int timeToSave = hourOfDay;
    if (hourOffset != hourOfDay) {
        timeToSave = (hourOfDay + (hourOfDay - hourOffset));
    }
    System.out.println("Time to save:" + timeToSave);

    /* When obtaining from db: */
    DateTime recalculatedTime = startOfDay.plusHours(timeToSave);

    System.out.println("Hour of time 'read' from db:" + recalculatedTime.getHourOfDay());
  }
}
Run Code Online (Sandbox Code Playgroud)

...或者基本上类似的东西。如果您选择走这条路,我会为其编写一个测试。您可以更改 HOUR_TO_TEST 以查看它是否超过了夏令时。