Java日期比较关闭一天

时间:2016-01-28 21:10:58

标签: java date calendar

我有Java方法比较两个Dates并返回它们之间的天数,但是它已经过了一天。

即使我在小时,分钟和秒之后0,计算仍然关闭。

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 个答案:

答案 0 :(得分:5)

嗯,正如您所看到的,您没有清除毫秒,而1454544000000 - 1453939200030 = 604799970除以86400000就会得到6.99999965277777...,这意味着6被截断为int

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

注意:由于夏令时,这并不意味着你已经完成了。使用DST时,其中一个时间戳可能距离另一个时间为±1小时,因此您可能仍会遇到截断问题。

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

答案 1 :(得分:3)

  

今天= 1453939200030

时间以毫秒为单位,看起来您输入的Date有30毫秒的额外毫秒数。

当我减去30毫秒时,然后在计算器上进行数学计算,我得到7天。根据您的数据,我得到6.9999996527777777777777777777778,并且在long数学中,小数字会被截断为6

也将毫秒归零。

expDate.set(Calendar.MILLISECOND, 0);
todayDate.set(Calendar.MILLISECOND, 0);

答案 2 :(得分:0)

java.time

问题和其他答案使用过时的类。旧的日期时间类(例如与最早版本的Java捆绑在一起的java.util.Date/.Calendar)已被证明非常麻烦。这些旧类已被Java 8及更高版本中的java.time框架所取代。

正如其他答案正确指出的那样,问题是开始long右侧有30,无法进行全天计算。

Days-Days-Days定义

此外,您必须按天数定义您的意思。你的意思是按日期计算,所以1月3日到4日的任何时间都是一天即使时间是午夜之前和之后的一分钟?或者你是指一般的24小时时间块,而忽略了由于夏令时(DST)和其他异常而导致特定时区的特定日期不总是24小时的事实?

按日期计算天数

如果你想要前者,按日期计算,那么可以使用LocalDate类(仅限日期,没有时间或时区)和Period类(跨度)在java.time中找到的定义为年,月,日的计数。

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

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

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

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 |即时:2016-01-28T00:00:00.030Z / 2016-02-04T00:00:00Z | ZonedDate时间:2016-01-27T19:00:00.030-05:00 [美国/蒙特利尔] / 2016-02-03T19:00-05:00 [美国/蒙特利尔] | LocalDate:2016-01-27 / 2016-02-03 |期间:P7D |天:7

整天数

如果您想要计算一整天,请使用Days中的ThreeTen-Extra课程。请注意,在下面的输出中,如上所示,我们得到计数六(6)天而不是七(7)

ThreeTen-EXTRA

ThreeTen-Extra项目扩展了java.time。由构建java.time的相同人员运行。

between方法的行为未明确记录。实验表明它似乎基于24小时的时间段,而不是日期。将030替换为000,并尝试使用000替换最后030的stopMilli,以查看自己的行为。

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

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

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

daysObject:P6D | daysObjectCount:6

答案 3 :(得分:0)

为了解决我的问题,我已经将所提到的毫秒数归零,并且为了保持准确性并在必要时进行舍入,还要将长信号转换为双精度数。

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);