Joda-time-by-one error when counting days after 1918-03-24

Calculating the number of days between 1900-01-01 and the date after 1918-03-24 using Joda-Time seems to give the result individually.

Using Java 8 java.time gives the correct result. What is the reason for Joda-Time, not counting 1918-03-25 ?

Using Joda-time v2.9.9.

 public static void main(String[] args) { jodaDiff("1918-03-24"); javaDiff("1918-03-24"); jodaDiff("1918-03-25"); javaDiff("1918-03-25"); jodaDiff("1918-03-26"); javaDiff("1918-03-26"); jodaDiff("2017-10-10"); javaDiff("2017-10-10"); } private static void jodaDiff(String date) { DateTime start = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeZone.forID("UTC")); DateTimeFormatter dateDecoder = DateTimeFormat.forPattern("YYYY-MM-dd"); DateTime end = dateDecoder.parseDateTime(date); int diff = Days.daysBetween(start, end).getDays(); System.out.println("Joda " + date + " " + diff); } private static void javaDiff(String date) { LocalDate start = LocalDate.parse("1900-01-01"); LocalDate end = LocalDate.parse(date); int diff = (int) ChronoUnit.DAYS.between(start, end); System.out.println("Java " + date + " " + diff + "\n"); } 

Output:

Joda 1918-03-24 6656
Java 1918-03-24 6656

Joda 1918-03-25 6656
Java 1918-03-25 6657

Joda 1918-03-26 6657
Java 1918-03-26 6658

Yoda 2017-10-10 43015
Java 2017-10-10 43016

+5
source share
4 answers

The problem is that your DateTimeFormatter uses the default system time zone. Ideally, you should parse the LocalDate values ​​instead of DateTime , but you can fix it using UTC to format anyway:

 DateTimeFormatter dateDecoder = DateTimeFormat.forPattern("YYYY-MM-dd").withZoneUTC(); 

For parsing with LocalDate just use:

 org.joda.time.LocalDate start = new org.joda.time.LocalDate(1900, 1, 1); DateTimeFormatter dateDecoder = DateTimeFormat.forPattern("YYYY-MM-dd"); org.joda.time.LocalDate end = dateDecoder.parseLocalDate(date); 

(Obviously, you do not need to fully qualify it if you are not using Java 8.)

+8
source

@Jon Skeet answer is correct and direct. I just wanted to add more details about what is happening and why you got these results (as you in the comments ), and John also answered with a hint, which is also correct).

Your default JVM time zone is probably Europe/London (or any other that has a DST change on March 24 th 1918 ). You can verify this using DateTimeZone.getDefault() in Joda-Time and ZoneId.systemDefault() in Java 8.

The start date that you created in Jod is 1900-01-01T00:00Z ( January 1 st 1900 at midnight in UTC ). The end date, however, is only created using the year, month, and day. But DateTime also requires time (hour / minute / second / millisecond) and time zone. Since they are not specified, it sets midnight to the JVM time zone by default (which is not guaranteed by UTC - depending on the configuration of the JVM, you may get a different result).

Assuming your default time zone is London (how could I reproduce the problem), this is not happening in my default JVM time zone ( America/Sao_Paulo )). In March 2010, there was DST in London, so when you create an end date from 1918-03-25 , the result is: March 25 th 1981 at midnight in the London timezone - but because of the DST change, the result is 1918-03-25T00:00+01:00 - during DST, London uses the offset +01:00 , which means that it is one hour ahead of UTC (so this end date is equivalent to 1918-03-24T23:00Z - or March 24 th 1981 at 11:00 in UTC ).

Thus, the difference in hours is 159767, which is not enough to complete 6657 days, so the difference is 6656 days (rounding is always to the lowest value - the difference must be at least 159768 hours to complete 6657 days).

If you use LocalDate , then the time and effects of DST are not taken into account (a LocalDate has only day, month and year), and you get the correct difference. If you set the end date to UTC, you will also get the correct results, because UTC has no DST changes.


By the way, if you use Java 8 ZonedDateTime and use start date with UTC and end date with London time zone (instead of using LocalDate ), you will get the same difference in results.


Not directly related, but in Joda-Time you can use the DateTimeZone.UTC constant to indicate UTC - calling forID("UTC") redundant, since it returns a constant anyway ( DateTimeZone.forID("UTC")==DateTimeZone.UTC returns true ).

+3
source

Joda-time-by-one error when counting days after 1918-03-24

Try this, I fixed your program. It gives you an excluded answer compared to Java

 public static void main(String[] args) { jodaDiff("1918-03-24"); javaDiff("1918-03-24"); jodaDiff("1918-03-25"); javaDiff("1918-03-25"); jodaDiff("1918-03-26"); javaDiff("1918-03-26"); jodaDiff("2017-10-10"); javaDiff("2017-10-10"); } private static void jodaDiff(String date) { DateTime start = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeZone.forID("UTC")); DateTime end = new DateTime(date); int diff = Days.daysBetween(start.toLocalDate(), end.toLocalDate()).getDays(); System.out.println("Joda " + date + " " + diff); } private static void javaDiff(String date) { LocalDate start = LocalDate.parse("1900-01-01"); LocalDate end = LocalDate.parse(date); int diff = (int) ChronoUnit.DAYS.between(start, end); System.out.println("Java " + date + " " + diff + "\n"); } 
0
source
 DateTime start = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeZone.forID("UTC")); DateTimeFormatter dateDecoder = DateTimeFormat.forPattern("YYYY-MM-dd").withZone(DateTimeZone.forID("UTC")); 

When you create the first date, you fix the zone, and the second does not. Therefore, either delete the zone or install it in both places.

You can also convert DateTime to LocalDate, it also works for this example, but the first solution should be the best.

0
source

Source: https://habr.com/ru/post/1272491/


All Articles