有 Java 编程相关的问题?

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

Java日期比较以天为单位

我有一个Java方法,它比较两个Dates并返回它们之间的天数,但它以一天为间隔

即使在我计算出小时、分钟和秒之后,计算仍然是关闭的

public long compareDates(Date exp, Date today){
        TimeZone tzone = TimeZone.getTimeZone("America/New_York");
        Calendar expDate = Calendar.getInstance();
        Calendar todayDate = Calendar.getInstance();

        expDate.setTime(exp);
        todayDate.setTime(today);

        expDate.set(Calendar.HOUR_OF_DAY, 0);
        expDate.set(Calendar.MINUTE, 0);
        expDate.set(Calendar.SECOND, 0);

        todayDate.set(Calendar.HOUR_OF_DAY, 0);
        todayDate.set(Calendar.MINUTE, 0);
        todayDate.set(Calendar.SECOND, 0);

        logger.info("Today = " + Long.toString(todayDate.getTimeInMillis()) + " Expiration = " + Long.toString(expDate.getTimeInMillis()));

        expDate.setTimeZone(tzone);
        todayDate.setTimeZone(tzone);

        return (expDate.getTimeInMillis()-todayDate.getTimeInMillis())/86400000;
    }

输出

Today = 1453939200030 Expiration = 1454544000000

1/28和2/4之间有7天,但这会返回6天


共 (4) 个答案

  1. # 1 楼答案

    爪哇。时间

    这个问题和其他答案使用了过时的课程。旧的日期时间类,比如java。util。日期/。事实证明,与最早版本的Java捆绑在一起的日历相当麻烦。这些旧类已被Java8及更高版本中的java.time框架取代

    正如其他答案正确指出的那样,问题在于开始long在右边有30,排除了一整天的计算

    天数定义

    此外,你必须定义天数的含义。你的意思是按日期计数,所以1月3日的任何时间到4日的任何时间都是一天,即使时间是午夜前后一分钟?或者,你的意思是计算一个通用的24小时时间段,而忽略一个事实,即由于夏令时(DST)和其他异常情况,特定时区中的特定日期并不总是24小时长

    按日期计算天数

    如果想要前者,请按日期计数,然后使用java中的LocalDate类(一个只有日期,没有一天中的时间,也没有时区)和Period类(定义为年、月、日计数的时间跨度)。时间到了

    定义你的输入。使用long而不是int。这些数字显然代表了自UTC 1970年第一个时刻以来的毫秒计数

    long startMilli = 1_453_939_200_030L;
    long stopMilli = 1_454_544_000_000L;
    

    将这些long数字转换为Instant对象,这是UTC时间轴上的一个时刻

    Instant startInstant = Instant.ofEpochMilli ( startMilli );
    Instant stopInstant = Instant.ofEpochMilli ( stopMilli );
    

    定义要考虑日历日期的时区。请注意,时区对于定义日期至关重要。全球各地的日期并不同时相同。日期因时区而异

    ZoneId zoneId = ZoneId.of ( "America/Montreal" );
    

    将该时区应用于每个Instant以生成ZonedDateTime

    ZonedDateTime startZdt = ZonedDateTime.ofInstant ( startInstant , zoneId );
    ZonedDateTime stopZdt = ZonedDateTime.ofInstant ( stopInstant , zoneId );
    

    要获得Period,我们需要“本地”日期。“本地”是指任何特定的地点,一个通用的日期值。LocalDate类不包含时区,但在确定ZonedDateTime时,将应用LocalDate中包含的时区

    LocalDate startLocalDate = startZdt.toLocalDate ();;
    LocalDate stopLocalDate = stopZdt.toLocalDate ();
    

    将我们的时间跨度定义为通用天数的计数,单位为Period

    Period period = Period.between ( startLocalDate , stopLocalDate );
    

    询问Period以询问包含的通用天数

    int days = period.getDays ();
    

    转储到控制台

    System.out.println ( "milli: " + startMilli + "/" + stopMilli + " | Instant: " + startInstant + "/" + stopInstant + " | ZonedDateTime: " + startZdt + "/" + stopZdt + " | LocalDate: " + startLocalDate + "/" + stopLocalDate + " | period: " + period + " | days: " + days );
    

    milli: 1453939200030/1454544000000 | Instant: 2016-01-28T00:00:00.030Z/2016-02-04T00:00:00Z | ZonedDateTime: 2016-01-27T19:00:00.030-05:00[America/Montreal]/2016-02-03T19:00-05:00[America/Montreal] | LocalDate: 2016-01-27/2016-02-03 | period: P7D | days: 7

    计算整日

    如果需要计算整天的天数,请使用ThreeTen-Extra中的^{}类。请注意,在下面的输出中,我们得到了六(6)天的计数,而不是如上所示的七(7)

    额外加收30美元

    ThreeTen-Extra项目扩展了java。时间由那些开发java的人运营。时间到了

    ^{}方法的行为没有明确的记录。实验表明,它似乎是基于24小时的时间段,而不是日期。将030替换为000,并尝试将stopMilli中的最后一个000替换为030,以便自己查看行为

    Days daysObject = Days.between ( startZdt , stopZdt );
    int daysObjectCount = daysObject.getAmount ();
    

    转储到控制台。您在输出中看到的P6D字符串是根据ISO 8601标准中定义的格式生成的。java中默认使用此标准。所有解析和生成日期时间值的文本表示的时间。这些标准格式非常合理和有用,所以请浏览一下链接的维基百科页面

    System.out.println ( "daysObject: " + daysObject + " | daysObjectCount: " + daysObjectCount );
    

    daysObject: P6D | daysObjectCount: 6

  2. # 2 楼答案

    Today = 1453939200030

    时间是以毫秒为单位的,看起来你输入的Date有30个额外的毫秒

    当我减去30毫秒,然后在计算器上计算,我得到7天。根据你的数字,我得到6.9999996527777777777777777777778,在long数学中,十进制数字被截断为6

    把毫秒也归零

    expDate.set(Calendar.MILLISECOND, 0);
    todayDate.set(Calendar.MILLISECOND, 0);
    
  3. # 3 楼答案

    为了解决我的问题,我已经将上面提到的毫秒归零,并将长数转换为双倍,以便在必要时保持精度和圆度

    expDate.setTime(exp);
    todayDate.setTime(today);
    expDate.setTimeZone(tzone);
    todayDate.setTimeZone(tzone);
    
    expDate.set(Calendar.HOUR_OF_DAY, 0);
    expDate.set(Calendar.MINUTE, 0);
    expDate.set(Calendar.SECOND, 0);
    expDate.set(Calendar.MILLISECOND, 0);
    
    todayDate.set(Calendar.HOUR_OF_DAY, 0);
    todayDate.set(Calendar.MINUTE, 0);
    todayDate.set(Calendar.SECOND, 0);
    todayDate.set(Calendar.MILLISECOND, 0);
    
    double diff = ((double)expDate.getTimeInMillis()-(double)todayDate.getTimeInMillis())/86400000;
    
    return Math.round(diff);
    
  4. # 4 楼答案

    正如你所看到的,你没有清除毫秒,并且1454544000000 - 1453939200030 = 604799970除以86400000得到6.99999965277777...,这意味着当被截断为int6

    现在,如果你也清除毫秒,今天变成1453939200000,这将导致你回答7

    注意:这并不意味着你完成了,因为夏令时。使用DST时,其中一个时间戳可能与另一个时间戳相差±1小时,因此可能仍然存在截断问题

    这是对你特定问题的回答。尝试在Java中搜索如何正确查找日期之间的天数