2

我正在解决将仅表示当前日期(即// 2013-03-10 00:00:00)的 GregorianCalendar 转换为 java.util.Date 对象的问题。这个测试背后的想法是取两个日期——一个只有当前日期,一个只有当前时间(即// 1970-01-01 12:30:45),并将它们组合成一个代表日期的日期和时间 (2013-03-10 12:30:45)。

在 DST 切换发生的那一天,测试失败 - 因为将 GregorianCalendar 转换为日期对象(Date date = dateCal.getTime(); 在下面的代码中)损失了一个小时,因此回滚到 (2013-03-09 23:00:00)。我怎样才能让这不会发生?

public static Date addTimeToDate(Date date, Date time) {
    if (date == null) {
        throw new IllegalArgumentException("date cannot be null");
    } else if (time == null) {
        throw new IllegalArgumentException("time cannot be null");
    } else {
        Calendar timeCal = GregorianCalendar.getInstance();
        timeCal.setTime(time);

        long timeMs = timeCal.getTimeInMillis() + timeCal.get(Calendar.ZONE_OFFSET) + timeCal.get(Calendar.DST_OFFSET);
        return addMillisecondsToDate(date, timeMs);
    }
}


@Test
public void testAddTimeToDate() {
    Calendar expectedCal = Calendar.getInstance();
    Calendar dateCal = Calendar.getInstance();
    dateCal.clear();
    dateCal.set(expectedCal.get(Calendar.YEAR), expectedCal.get(Calendar.MONTH), expectedCal.get(Calendar.DAY_OF_MONTH));

    Calendar timeCal = Calendar.getInstance();
    timeCal.clear();
    timeCal.set(Calendar.HOUR_OF_DAY, expectedCal.get(Calendar.HOUR_OF_DAY));
    timeCal.set(Calendar.MINUTE, expectedCal.get(Calendar.MINUTE));
    timeCal.set(Calendar.SECOND, expectedCal.get(Calendar.SECOND));
    timeCal.set(Calendar.MILLISECOND, expectedCal.get(Calendar.MILLISECOND));

    Date expectedDate = expectedCal.getTime();
    Date date = dateCal.getTime();
    Date time = timeCal.getTime();

    Date actualDate = DateUtil.addTimeToDate(date, time);

    assertEquals(expectedDate, actualDate);
}
4

4 回答 4

0

为什么在计算中包括时区偏移?当您在 Java 中使用毫秒时,它们始终使用 UTC。你不需要做任何额外的转换。

您最大的问题可能是尝试手动进行这些日期/时间计算。您应该使用 Calendar 类本身来处理计算。

于 2013-03-14T14:46:28.167 回答
0

这就是我最终重构我的方法以补偿由于 DST 而损失/获得的时间的方式:

public static Date addTimeToDate(Date date, Date time) {
    if (date == null) {
        throw new IllegalArgumentException("date cannot be null");
    } else if (time == null) {
        throw new IllegalArgumentException("time cannot be null");
    } else {
        Calendar dateCal = GregorianCalendar.getInstance();
        dateCal.setTime(date);

        Calendar timeCal = GregorianCalendar.getInstance();
        timeCal.setTime(time);
        int zoneOffset = timeCal.get(Calendar.ZONE_OFFSET);

        if (dateCal.get(Calendar.MONTH) == Calendar.MARCH) {
            if (Calendar.SUNDAY == dateCal.get(Calendar.DAY_OF_WEEK) && dateCal.get(Calendar.DAY_OF_MONTH) >= 7
                    && dateCal.get(Calendar.DAY_OF_MONTH) <= 14 && timeCal.get(Calendar.HOUR_OF_DAY) >= 3) {
                zoneOffset -= TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS);
            }
        } else if (dateCal.get(Calendar.MONTH) == Calendar.NOVEMBER) {
            if (Calendar.SUNDAY == dateCal.get(Calendar.DAY_OF_WEEK) && dateCal.get(Calendar.DAY_OF_MONTH) <= 7
                    && timeCal.get(Calendar.HOUR_OF_DAY) >= 3) {
                zoneOffset += TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS);
            }
        }
        long timeMs = timeCal.getTimeInMillis() + zoneOffset + timeCal.get(Calendar.DST_OFFSET);
        return addMillisecondsToDate(date, timeMs);
    }
}

我不喜欢这种方法,因为如果 DST 的规则发生变化,那么这种方法就需要更新。有没有可以执行类似功能的库?

于 2013-03-19T14:56:13.957 回答
0

我试过了,并没有什么不同。甚至不同的语言环境,并用日历替换了 GregorianCalendar..

用过的:

private static Date addMillisecondsToDate(Date date, long timeMs) {
    return new Date(date.getTime() + timeMs);
}

即将推出的 Java 8 具有更好的日期/时间支持。

于 2013-03-14T15:17:50.537 回答
0
于 2018-02-05T19:50:24.907 回答