有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

两个java日期之间的差异

我提到生产项目中的一种方法与日期不符,但我不能直接替换它,因为它已经在生产中很长时间了。我已经创建了一个新方法,它工作正常,但我不明白为什么第一个方法工作错误

旧方法(工作错误):

public static Integer getNumberOfDays(Date startDate, Date endDate) {
    TimeZone.setDefault((TimeZone.getTimeZone("Europe/Moscow")));

    startDate.setHours(00);
    startDate.setMinutes(00);
    startDate.setSeconds(00);

    endDate.setHours(23);
    endDate.setMinutes(59);
    endDate.setSeconds(59);

    Calendar cal1 = Calendar.getInstance();
    cal1.setTime(startDate);

    Calendar cal2 = Calendar.getInstance();
    cal2.setTime(endDate);

    Calendar date = (Calendar) cal1.clone();
    int daysBetween = 0;
    while (date.before(cal2)){
        date.add(Calendar.DAY_OF_MONTH, 1);
        daysBetween++;
    }
    return daysBetween;
}

新方法:

public static Integer getNumberOfDaysSecondVersion(Date startDate, Date endDate) {
    long difference = startDate.getTime() - endDate.getTime();
    float daysBetween = (difference / (1000*60*60*24));
    return (int) daysBetween > 0 ? (int) daysBetween : 0;
}

以下是我对两者的称呼:

DateFormat formated = new SimpleDateFormat("yyyy-MM-dd");

    System.out.println(Calculation.getNumberOfDays(
            formated.parse("2018-06-14"),
            formated.parse("2018-06-06")
    ));

    System.out.println(Calculation.getNumberOfDaysSecondVersion(
            format.parse("2018-06-14"),
            format.parse("2018-06-06"))
    );

输出:

0
8

请帮忙


共 (3) 个答案

  1. # 1 楼答案

    您对这两个版本使用了非常不同的算法

    旧版本会一直在开始日期后添加天数,直到结束日期之后

    新版本从开始日期减去结束日期,然后除以一天中的毫秒数

    这意味着,对于第一个版本,开始日期必须在结束日期之前,对于第二个版本,开始日期必须在结束日期之后。您为第一个版本提供的参数的开始日期晚于结束日期,因此返回0

    要解决此问题,只需反转两个参数:

    System.out.println(getNumberOfDays(
            formated.parse("2018-06-06"),
            formated.parse("2018-06-14")
    ));
    

    或者,在计算它们之间的差异之前,先检查哪个日期先到

    顺便说一下,您的第一个版本似乎比第二个版本多输出一个。你似乎想要8天的结果。这意味着您的第一个版本有一个off-by-1错误。您可以通过从计数结果中减去1来解决此问题

    请记住,只要有可能,就要始终使用java.time

  2. # 2 楼答案

    你的旧方法是正确的。当开始日期晚于结束日期时,返回0。你的电话就是这样

    您的新方法从开始日期减去结束日期,这是错误的,应该是相反的。我还怀疑,它将在夏季时间(DST)和夏季时间(DST)之间的过渡中带来惊喜。虽然莫斯科目前不使用夏季时间,但从历史上看,至少在2010年之前是这样,如果政客们决定这样做的话,可能还会这样做

    也就是说,如果可以避免使用过时的日期和时间类DateFormatSimpleDateFormatCalendarDateTimeZone,那么您应该尝试一下。今天我们在^{}, the modern Java date and time API有了更好的表现。当然,在遗留代码中有老式的Date对象。在编写新方法时,我建议您将它们转换为现代的LocalDate并使用^{}

    ChronoUnit.DAYS.between(
        LocalDate.parse( "2018-06-14" ) ,
        LocalDate.parse( "2018-06-06" ) 
    )
    

    -8

    请注意,当旧方法设置默认时区时,它会影响JVM中运行的所有程序,并且可能会对程序的其他部分和其他程序造成严重的意外

  3. # 3 楼答案

    可能是因为startDate和endDate的时区不受默认时区设置的影响,因此当您基于它们设置日历时间(莫斯科时间)时,您正在转换时区,可能将00:00:00转换为前一天的21:00:00或其他

    编辑

    看到你的成果,很明显。。。您传入的开始日期与结束日期相比是在将来。原始方法使用一个只能向上计数的循环,而新方法则获取差值的绝对值