我有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.
答案 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捆绑在一起的java.util.Date/.Calendar)已被证明非常麻烦。这些旧类已被Java 8及更高版本中的java.time框架所取代。
正如其他答案正确指出的那样,问题是开始long
右侧有30
,无法进行全天计算。
此外,您必须按天数定义您的意思。你的意思是按日期计算,所以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项目扩展了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);