简体   繁体   English

两个日期之间的差异,以天为单位,各不相同

[英]Difference between two dates, in days, varies

Date d = new Date(today.getTimeInMillis());
Date d1 = new Date(dueDate.getTimeInMillis());

int daysUntil = (int) ((d1.getTime() - d.getTime())/ (1000 * 60 * 60 * 24));

Using the above code, where today is a calendar set to 00:00 on the current day, and dueDate is set to 00:00 on the date I am comparing today to, my results from this differ. 使用上面的代码, today的日历设置为当天00:00,而dueDate设置为我今天比较的日期00:00,我的结果不同。

There is something in this which varies, making my output either x or x+1 where x is the correct answer. 这有些变化,使我的输出x或x + 1,其中x是正确的答案。

What is the issue here, and what can I do to make it more stable? 这里有什么问题,我该怎么做才能让它更稳定?

Vague Question 模糊的问题

You do not provide actual values, so we cannot determine precisely the problem. 您没有提供实际值,因此我们无法准确确定问题。 We do not know what the today and dueDate variables are. 我们不知道todaydueDate变量是什么。

Outmoded 陈旧

The question is now outmoded, as the troublesome old date-time classes including java.util.Date/.Calendar have been supplanted by the new java.time framework. 现在这个问题已经过时了,因为新的java.time框架已经取代了麻烦的旧日期时间类,包括java.util.Date/.Calendar。 See Tutorial . 请参阅教程 Defined by JSR 310 , inspired by Joda-Time , and extended by the ThreeTen-Extra project. JSR 310定义,灵感来自Joda-Time ,并由ThreeTen-Extra项目扩展。

In java.time: 在java.time中:

  • An Instant is a moment on the timeline in UTC. Instant是UTC时间轴上的一个时刻。
  • A ZoneId represents a time zone. ZoneId表示时区。 Use proper time zone names, never the 3-4 letter codes like "EST" or "IST" as they are neither standardized nor unique. 使用正确的时区名称,从不使用像“EST”或“IST”这样的3-4个字母代码,因为它们既不是标准化也不是唯一的。
  • Conceptually, ZonedDateTime = Instant + ZoneId. 从概念上讲, ZonedDateTime = Instant + ZoneId。

ThreeTen-Extra ThreeTen-EXTRA

Unfortunately, java.time does not include a facility for calculating days elapsed between date-time values. 遗憾的是,java.time不包含用于计算日期时间值之间经过的天数的工具。 We can use the ThreeTen-Extra project and its Days class with between method to provide that calculation. 我们可以使用ThreeTen-Extra项目及其Days类与方法between来提供该计算。 The ThreeTen-Extra project is a collection of features deemed non-essential for java.time during the JSR process. ThreeTen-Extra项目是在JSR过程中被认为对于java.time不重要的功能的集合。

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );
ZonedDateTime then = now.minusDays ( 4 );
ZonedDateTime due = now.plusDays ( 3 );
Integer days = org.threeten.extra.Days.between ( then , due ).getAmount ();

Dump to console. 转储到控制台。

System.out.println ( "From then: " + then + " to due: " + due + " = days: " + days );

From then: 2015-10-31T16:01:13.082-04:00[America/Montreal] to due: 2015-11-07T16:01:13.082-05:00[America/Montreal] = days: 7 从那时起:2015-10-31T16:01:13.082-04:00 [美国/蒙特利尔]到期日期:2015-11-07T16:01:13.082-05:00 [美国/蒙特利尔] =天数:7

Joda-Time 乔达时间

For Android or older versions of Java, use the excellent Joda-Time library. 对于Android或旧版本的Java,请使用优秀的Joda-Time库。

The Days class is smart and handles anomalies such as Daylight Saving Time (DST). Days类很聪明,可以处理夏令时 (DST)等异常情况。

Note that unlike java.util.Date, a Joda-Time DateTime object knows its own time zone. 请注意,与java.util.Date不同,Joda-Time DateTime对象知道自己的时区。

// Specify a time zone rather than rely on default.
DateTimeZone timeZone = DateTimeZone.forID( "America/Regina" ); // Or "Europe/London".

DateTime now = new DateTime( timeZone );
DateTime startOfToday = now.withTimeAtStartOfDay();

DateTime fewDaysFromNow = now.plusDays( 3 );
DateTime startOfAnotherDay = fewDaysFromNow.withTimeAtStartOfDay();

Days days = Days.daysBetween( startOfToday, startOfAnotherDay );

Dump to console… 转储到控制台......

System.out.println( days.getDays() + " days between " + startOfToday + " and " + startOfAnotherDay + "." );

When run… 跑的时候......

3 days between 2014-01-21T00:00:00.000-06:00 and 2014-01-24T00:00:00.000-06:00.

There are mainly two reasons why your code is broken: 您的代码被破坏主要有两个原因:

  • second parts or millisecond fractions (you might have overlooked) 第二部分或毫秒分数(您可能忽略了)
  • daylight saving effects 夏令时效果

I demonstrate and explain the second reason. 我演示并解释了第二个原因。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = sdf.parse("2016-03-20");
Date d2 = sdf.parse("2016-03-28");
int daysUntil = (int) ((d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24));
System.out.println(daysUntil); // 7 (should be 8)

The code was run in timezone "Europe/Berlin". 该代码在时区“Europe / Berlin”中运行。 Due to the change from winter time to summer time causing a jump of clocks by one hour forward on 2016-03-27 at 2 am, there is one hour missing. 由于冬季到夏季时间的变化导致2016-03-27凌晨2点时钟前进一小时,所以有一个小时失踪。 One day has only 23 hours so the division by 24 yields zero resulting in counting one day less. 一天只有23个小时,所以除以24得到零,导致计算一天减少。

What can you do else? 你还能做什么?

Your workaround adding 1000 milliseconds to dueDate sounds as if you have overlooked possible millisecond deltas in your input. 您的解决方法将1000毫秒添加到dueDate听起来就好像您忽略了输入中可能的毫秒级别。 This might solve a special case but will usually not be sufficient to solve the daylight saving problem, too. 这可能会解决一个特殊情况,但通常也不足以解决夏令时问题。 Whatever you choose on base of java.util.Date it is a more or less an evil hack. 无论你在java.util.Date基础上选择什么,它或多或少是一个邪恶的黑客。

The best I have in mind (within the scope of Android-built-in stuff) is to construct an instance of java.util.GregorianCalendar and to add successively one day after one until you have passed the due-date, and then count how many days you have added . 我想到的最好(在Android内置的东西范围内)是构造一个java.util.GregorianCalendar的实例,并在一天之后连续添加,直到你通过截止日期,然后计算如何很多天你都添加了 Not elegant and errorprone because varying millisecond parts can easily be overlooked here, too. 不优雅和错误,因为这里也可以轻易忽略不同的毫秒部分。

Otherwise you can try various external libraries for this task. 否则,您可以尝试各种外部库来完成此任务。 There are four available on Android which can calculate elapsed days in an easy way. Android上有四种可以轻松计算经过的天数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM