1

I am converting data to Adabas (days) from Date in Java. But a have difference in dates when I use LocalDate and Calendar. I am using Java 8

public static void printNewLocalDateWithPlusDays(Long daysToAdd) {
        LocalDate initDateToCalculate = LocalDate.of(0, 1, 4);
        System.out.println("Initial Date To Calculate : " + initDateToCalculate);
        LocalDate dateCalculated = initDateToCalculate.plusDays(daysToAdd);
        System.out.println("Date calculated : " + dateCalculated);
}

public static void printSimpleDateFormatWithPlusDaysInCalendar(Long daysToAdd) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        try {
            calendar.setTime(sdf.parse("0000-01-04"));
            System.out.println("Initial Date To Calculate : " + sdf.format(calendar.getTime()));
        } catch (ParseException e) {
            e.printStackTrace();
        }

        calendar.add(Calendar.DAY_OF_MONTH, daysToAdd.intValue());
        Date time = calendar.getTime();
        String dateFormatted = sdf.format(time);
        System.out.println("Date calculated : " + dateFormatted);
}

public static void main(String[] args) {
        Long daysToAdd = 36580L;
        System.out.println("Print dates is less than or equal to " + daysToAdd + " days");
        System.out.println("Print Local Date");
        printNewLocalDateWithPlusDays(daysToAdd);
        System.out.println("----------");
        System.out.println("Print Calendar with SimpleDateFormat");
        printSimpleDateFormatWithPlusDaysInCalendar(daysToAdd);

        System.out.println("----------");
        System.out.println("Difference init here");
        System.out.println("----------");

        daysToAdd = 36581L;
        System.out.println("Print dates is greater than or equal to " + daysToAdd + " days");
        System.out.println("Print Local Date");
        printNewLocalDateWithPlusDays(daysToAdd);
        System.out.println("----------");
        System.out.println("Print Calendar with SimpleDateFormat");
        printSimpleDateFormatWithPlusDaysInCalendar(daysToAdd);
}

I expect the outputs of same, but the actual outputs is different. Why?

2 Answers2

1

Because (at least when I run your code), Calendar.getInstance() returns an instance of GregorianCalendar, and according to its javadoc (emphasis mine):

Historically, in those countries which adopted the Gregorian calendar first, October 4, 1582 (Julian) was thus followed by October 15, 1582 (Gregorian). This calendar models this correctly. Before the Gregorian cutover, GregorianCalendar implements the Julian calendar. The only difference between the Gregorian and the Julian calendar is the leap year rule. The Julian calendar specifies leap years every four years, whereas the Gregorian calendar omits century years which are not divisible by 400.

GregorianCalendar implements proleptic Gregorian and Julian calendars. That is, dates are computed by extrapolating the current rules indefinitely far backward and forward in time. As a result, GregorianCalendar may be used for all years to generate meaningful and consistent results.

Since you're constructing a date in the year 100, it's using the Julian calendar rule, which says that it's a leap year, so it prints Feb 29.

However, LocalDate uses the ISO-8601 calendar system, and its javadoc says (emphasis mine):

The ISO-8601 calendar system is the modern civil calendar system used today in most of the world. It is equivalent to the proleptic Gregorian calendar system, in which today's rules for leap years are applied for all time. For most applications written today, the ISO-8601 rules are entirely suitable. However, any application that makes use of historical dates, and requires them to be accurate will find the ISO-8601 approach unsuitable.

So it miscalculates the leap year, and prints March 1.

Community
  • 1
  • 1
azurefrog
  • 10,785
  • 7
  • 42
  • 56
0

LocalDate uses IsoChronology by default:

This chronology defines the rules of the ISO calendar system. This calendar system is based on the ISO-8601 standard, which is the de facto world calendar.

Wikipedia's article on ISO 8601 says:

ISO 8601 fixes a reference calendar date to the Gregorian calendar of 20 May 1875 as the date the Convention du Mètre (Metre Convention) was signed in Paris. However, ISO calendar dates before the Convention are still compatible with the Gregorian calendar all the way back to the official introduction of the Gregorian calendar on 1582-10-15. Earlier dates, in the proleptic Gregorian calendar, may be used by mutual agreement of the partners exchanging information. The standard states that every date must be consecutive, so usage of the Julian calendar would be contrary to the standard (because at the switchover date, the dates would not be consecutive).

Calendar is normally a GregorianCalendar.

GregorianCalendar is a hybrid calendar that supports both the Julian and Gregorian calendar systems with the support of a single discontinuity, which corresponds by default to the Gregorian date when the Gregorian calendar was instituted (October 15, 1582 in some countries, later in others). The cutover date may be changed by the caller by calling setGregorianChange().

So, they don't agree on dates before 1582-10-15, as demonstrated here:

LocalDate localDate = LocalDate.of(1582, Month.OCTOBER, 18);
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(1582, Calendar.OCTOBER, 18);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
for (int i = 0; i < 8; i++) {
    System.out.println(localDate + " vs " + dateFormat.format(calendar.getTime()));
    localDate = localDate.plusDays(-1);
    calendar.add(Calendar.DAY_OF_MONTH, -1);
}

Output

1582-10-18 vs 1582-10-18
1582-10-17 vs 1582-10-17
1582-10-16 vs 1582-10-16
1582-10-15 vs 1582-10-15
1582-10-14 vs 1582-10-04
1582-10-13 vs 1582-10-03
1582-10-12 vs 1582-10-02
1582-10-11 vs 1582-10-01

Andreas
  • 154,647
  • 11
  • 152
  • 247