为什么特定日期(03/12/2018)之间的差异不是确切的天数?

时间:2018-01-03 21:01:11

标签: java date

我正面临Java的一个奇怪问题(版本6,7,8)。在这段代码中,我试图计算两个日期之间的日期差异,这段代码给出了我在03/12/2018和01/04/2018之间的日期差异,为66.958天,而不是67天,这有点令人惊讶。我从未见过这种行为。

为了证明这一理论,你可以尝试在03/11/2018之前的任何日期,这是一个简单的数学。请告知你们的想法。我已经尝试了与Java捆绑在一起的ChronoUnit类,它正确地计算了天数,但只是想知道这里发生了什么以及你是否有任何意见。

static  void dateLogic1() throws ParseException{
       String matYear1 = "03/11/2018";
       String matYear2 = "03/12/2018";

       String stlDate = "01/04/2018";


       java.util.Date mtYear1 = new SimpleDateFormat("MM/dd/yyyy").parse(matYear1);
       java.util.Date mtYear2 = new SimpleDateFormat("MM/dd/yyyy").parse(matYear2);


       java.util.Date stYear = new SimpleDateFormat("MM/dd/yyyy").parse(stlDate);

       long time1 = mtYear1.getTime();
       long time2 = mtYear2.getTime();
       long time4 = stYear.getTime();


       double diff1 =  (double) (mtYear1.getTime()-stYear.getTime()) /( 24 * 60 * 60 * 1000);
       double diff2 =  (double) (mtYear2.getTime()-stYear.getTime()) /( 24 * 60 * 60 * 1000);

       System.out.println("Date Diff between "+ mtYear1 +" & "+ stYear +" is " + diff1 );
       System.out.println("Date Diff between "+ mtYear2  +" & "+ stYear +" is " + diff2 );

   }

2 个答案:

答案 0 :(得分:8)

这与夏令时有关。 2018年3月11日凌晨2点,很多地方都损失了一个小时。如果您将该小时转换为一天的一小部分(1/24),结果是67和66.958之间的差异。

编辑: Date.getTime()返回自Date对象表示的1970年1月1日00:00:00 GMT以来的毫秒数。因为你失去了一个小时的千分之一,这就是分数小时丢失的原因。

答案 1 :(得分:3)

TL;博士

Duration.between( ZonedDateTime , ZonedDateTime )

详细

Sam M的回答和scottb的评论都是正确的。

你正在使用现在遗留下来的麻烦的旧日期时间类,取而代之的是java.time类。

LocalDate start = LocalDate.of( 2018 , Month.JANUARY , 4 ) ;
LocalDate stop = LocalDate.of( 2018 , Month.MARCH , 12 ) ;
long days = ChronoUnit.DAYS.between( start , stop ) ;

如果您想要时刻而不是日期,则必须指定时区。对于任何特定时刻,日期在全球范围内因地区而异。

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;

让java.time确定一天的第一时刻,因为它并不总是在00:00。

我们添加一天来计算最后一天的整个长度。

ZonedDateTime zdtStart = start.atZone( z ) ; 
ZonedDateTime zdtStop = stop.plusDays( 1 ).atZone( z ) ; 

使用Duration对象计算经过纳秒级分辨率的时间。

Duration d = Duration.between( zdtStart , zdtStop ) ;

将标准ISO 8601格式的字符串表示为字符串。

String output = d.toString() ;  // Generate string in standard ISO 8601 format. 

经验教训:

  • 不要忽视/忘记时区。
  • 避免像瘟疫这样的遗留日期时间类。始终使用业界领先的java.time类。永远不要滚动自己的日期时间处理。
  • 天不总是24小时。
  • 天不总是从00:00开始。
  • 使用半开方法定义开头包含的时间跨度,而结尾是独占的。

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore