Date change when converting from XMLGregorianCalendar to calendar

When testing a web service that displays date and time types between systems, I noticed that sending any date before the start of the Gregorian calendar time led to a loss of accuracy when casting to the final type, and the final result was always slightly ahead in time for several days .

I narrowed the problem to the exact line, but I still can’t understand why this is done so, from the documentation it says that the Julian calendar is used for dates before the start of the Gregorian calendar: October 15, 1582.

The problem line is in the range from XMLGregorianCalendarto GregorianCalendar, line 78: calendarDate = argCal.toGregorianCalendar(); When the time is taken from calendarDateline 86: The cal.setTime(calendarDate.getTime());time returns 2 days earlier than it should be, January 3, and not January 01, as you will see in the output below.

Here is an example of a program that I did to show the casting process to the end:

import java.sql.Date;
import java.util.Calendar;
import java.util.GregorianCalendar;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;



public class TestDateConversions {

    public static void main(String[] args)
    {
        TestDateConversions testDates = new TestDateConversions();
        try
        {
            XMLGregorianCalendar testDate1 = DatatypeFactory.newInstance().newXMLGregorianCalendar();
            testDate1.setYear(0001);
            testDate1.setMonth(01);
            testDate1.setDay(01);
            System.out.println("Start date: "+testDate1.toString() +"\n**********************");

            testDates.setXMLGregorianCalendar(testDate1);
            System.out.println("\nNull given \n"+ "**********");
            testDates.setXMLGregorianCalendar(null);
        }
        catch(Exception e)
        {
            System.out.println(e);
        }
    }


    public void setXMLGregorianCalendar(XMLGregorianCalendar argCal)
    {
        GregorianCalendar calendarDate;
        if (argCal != null)
        {
            calendarDate = argCal.toGregorianCalendar();
            System.out.println("XMLGregorianCalendar time: " + argCal.getHour() + ":"+argCal.getMinute()+":"+argCal.getSecond());
            System.out.println("XMLGregorianCalendar time(ms): "+argCal.getMillisecond());
            System.out.println("XMLGregorianCalendar -> GregorianCalendar: "+calendarDate.get(GregorianCalendar.YEAR) + "-"+(calendarDate.get(GregorianCalendar.MONTH)+1) + "-"+calendarDate.get(GregorianCalendar.DAY_OF_MONTH));
            System.out.println("!!!!PROBLEM AREA!!!!");
            Calendar cal = Calendar.getInstance();
            System.out.println("-- New Calendar instance: "+cal.get(Calendar.YEAR) + "-"+(cal.get(Calendar.MONTH)+1)+"-"+cal.get(Calendar.DAY_OF_MONTH));
            System.out.println("-- Calling Calendar.setTime(GregorianCalendar.getTime())");
            cal.setTime(calendarDate.getTime());
            System.out.println("-- calendarDate.getTime() = " + calendarDate.getTime() + " <-- time is incorrect");
            System.out.println("-- Calendar with time set from GregorianCalendar: "+cal.get(Calendar.YEAR) + "-"+(cal.get(Calendar.MONTH)+1)+"-"+cal.get(Calendar.DAY_OF_MONTH) + " <-- day is increased here");
            setCalendar(cal);
        }
        else 
        {
            setCalendar(null);
        }
    }

    public void setCalendar(Calendar argCal)
    {
        if (argCal != null)
        {
            Date date = new Date(argCal.getTimeInMillis());
            System.out.println("Calendar to Date: "+date);
            setDate(date);
        }
        else
        {
            setDate(null);
        }

    }

    public void setDate(Date argDate)
    {
        try
        {
            if (argDate == null)
            {
                Calendar cal  = new GregorianCalendar(1,0,1);
                Date nullDate = new Date(cal.getTimeInMillis());
                System.out.println("Null Calendar created: "+cal.get(Calendar.YEAR) + "-"+(cal.get(Calendar.MONTH)+1)+"-"+cal.get(Calendar.DAY_OF_MONTH));
                System.out.println("Null Date created: "+nullDate);
            }
            else 
            {
                System.out.println("Final date type: "+argDate);
            }
        }
        catch (Exception  ex)
        {
            System.out.println(ex);
        }
    }
}
+5
source share
2 answers

Excerpt from XMLGregorianCalendar.toGregorianCalendar()JavaDoc on how they instantiate GregorianCalendar:

Get a clean Gregorian calendar by calling GregorianCalendar.setGregorianChange (new date (Long.MIN_VALUE)).

This means that the created calendar will be prolific and will not switch to the Julian calendar, as is done by default for old dates. Then the problem is here:

  • argCal.toGregorianCalendar() - XMLGregorianCalendar GregorianCalendar ( - . )
  • cal.setTime(calendarDate.getTime());
    • timestamp
    • , 1582 .

:


. , Java Date Calendar API ( ) . Java 8 JSR-310 ( JodaTime ).

, ( ) :

- , java.util.Date. . , . , . ... , , , . , , 0 10 . gregorian calendar - .

XMLGregorianCalendar vs GregorianCalendar:

  • XML , , , gregorian.
  • Java GregorianCalendar "", ,
  • XMLGregorianCalendar GregorianCalendar , (. JavaDoc ).

:

, GregorianCalendar , - , 3 . , 3 , - , ? , , ! . , :) [JSR-310 ].

, gregorian (.. gregorian ), :

Calendar calendar = Calendar.getInstance();
((GregorianCalendar) calendar).setGregorianChange(new Date(Long.MIN_VALUE));

: calendar.getTime() . , , java.util.Date.toString() ( System.out.println) Calendar, . ? , ( , :))?


2

// Get XML gregorian calendar
XMLGregorianCalendar xmlCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar();
xmlCalendar.setYear(1); // Watch for octal number representations (you had there 0001)
xmlCalendar.setMonth(1);
xmlCalendar.setDay(1);

// Convert to Calendar as it is easier to work with it
Calendar calendar = xmlCalendar.toGregorianCalendar(); // Proleptic for old dates

// Convert to default calendar (will misinterpret proleptic for Julian, but it is a workaround)
Calendar result = Calendar.getInstance();
result.setTimeZone(calendar.getTimeZone());
result.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
result.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
result.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH));
result.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY));
result.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE));
result.set(Calendar.SECOND, calendar.get(Calendar.SECOND));
result.set(Calendar.MILLISECOND, calendar.get(Calendar.MILLISECOND));

System.out.println(result.getTime());

Disclamer: ( - , XML), OP (. ).

+9

, . , ( ) 0001-01-01, , 0001-01-03 . 1001-01-01, , 1000-12-26. , . 4- , ( ).

XMLGregorianCalendar com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl, toGregorianCalendar() :

    result = new GregorianCalendar(tz, locale);
    result.clear();
    result.setGregorianChange(PURE_GREGORIAN_CHANGE);

GregorianCalendar, 1583 ( 1970 ) . , , , GregorianCalendar...

. , :

public static void main(String...args) {
    GregorianCalendar gcal = new GregorianCalendar();
    gcal.clear();
    gcal.setGregorianChange(new Date(Long.MIN_VALUE));
    gcal.set(Calendar.YEAR, 1);  // or any other year before 1582
    gcal.set(Calendar.MONTH, Calendar.JANUARY);
    gcal.set(Calendar.DATE, 1);

    Date d = gcal.getTime();
    System.out.println(d);
}

, , - getGregorianChange()... ( ), , , . Date, getTime(), , . , , , .

0

All Articles