1

在处理从我通过 LDAP 访问的活动目录返回的结果时,我一直试图了解日期和时间计算的不同结果。我在某处读到某些差异可能是由夏令时引起的?我不明白为什么使用 1601 年 1 月 1 日的日历来更正时间会产生四个小时的差异,或者为什么在 Java 中添加天数会产生一个小时的差异。我假设答案是我应该在尝试转换原始值之前对原始值进行所有算术运算,但这不能回答为什么用日历更正时间会有四个小时的差异。

这是我的例子:

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import org.apache.commons.lang3.time.DateUtils;

public class Test {
    public static void main(String[] args) {
        Long millisecondCorrector = 10000L;
        Long epochCorrector = 11644473600000L;
        GregorianCalendar win32Epoch = new GregorianCalendar(1601, Calendar.JANUARY, 1, 0, 0, 0);

        Long maxPwdAge = -78624000000000L;
        Long pwdLastSet = 130256481664603612L;

        System.out.println("Max Password Age in milliseconds                               : " + (Math.abs(maxPwdAge) / millisecondCorrector));
        System.out.println("Max Password Age in days                                       : " + (Math.abs(maxPwdAge) / millisecondCorrector / DateUtils.MILLIS_PER_DAY));
        System.out.println("***********************************************************************************************************");
        System.out.println("Password Last Set (Static corrector)                           : " + new Date(pwdLastSet / millisecondCorrector - epochCorrector));
        System.out.println("Password Last Set (Calendar corrector)                         : " + new Date(pwdLastSet / millisecondCorrector + win32Epoch.getTimeInMillis()));
        System.out.println("***********************************************************************************************************");
        System.out.println("Password Expiration (Static corrector)                         : " + new Date((pwdLastSet + Math.abs(maxPwdAge)) / millisecondCorrector - epochCorrector));
        System.out.println("Password Expiration (Day arithmetic w/ static corrector)       : " + DateUtils.addDays(new Date(pwdLastSet / millisecondCorrector - epochCorrector), (int) (Math.abs(maxPwdAge) / millisecondCorrector / DateUtils.MILLIS_PER_DAY)));
        System.out.println("Password Expiration (Calendar corrector)                       : " + new Date((pwdLastSet + Math.abs(maxPwdAge)) / millisecondCorrector + win32Epoch.getTimeInMillis()));
        System.out.println("Password Expiration (Day arithmetic w/ calendar corrector)     : " + DateUtils.addDays(new Date(pwdLastSet / millisecondCorrector + win32Epoch.getTimeInMillis()), (int) (Math.abs(maxPwdAge) / millisecondCorrector / DateUtils.MILLIS_PER_DAY)));
    }

}

以下是结果:

Max Password Age in milliseconds                               : 7862400000
Max Password Age in days                                       : 91
***********************************************************************************************************
Password Last Set (Static corrector)                           : Mon Oct 07 15:36:06 EDT 2013
Password Last Set (Calendar corrector)                         : Mon Oct 07 20:36:06 EDT 2013
***********************************************************************************************************
Password Expiration (Static corrector)                         : Mon Jan 06 14:36:06 EST 2014
Password Expiration (Day arithmetic w/ static corrector)       : Mon Jan 06 15:36:06 EST 2014
Password Expiration (Calendar corrector)                       : Mon Jan 06 19:36:06 EST 2014
Password Expiration (Day arithmetic w/ calendar corrector)     : Mon Jan 06 20:36:06 EST 2014

作为后续行动,我想我应该问是否有处理这类计算的好库?好像这段代码已经写了很多次了!

4

1 回答 1

0

我怀疑默认时区有问题。例如,如果您的 JVM 位于GMT+1win32Epoch则不是日期午夜,而是1600-12-31T23:00:00.000Z. 始终阅读 JavaDoc 并在有意义的地方使用基于时区的构造函数。

您还在非 UTC 时区 (EDT & EST) 中打印日期。这可能会使计算及其结果更加不清楚。


对于日期时间计算,我只能推荐Joda Time。这个框架作为新的日期和时间 API的基础,它将出现在 Java 8 中。

于 2013-10-15T21:43:06.630 回答