String date to xmlgregoriancalendar conversion
Found the solution as below.... posting it as it could help somebody else too :)
DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = format.parse("2014-04-24 11:15:00");
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(date);
XMLGregorianCalendar xmlGregCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
System.out.println(xmlGregCal);
Output:
2014-04-24T11:15:00.000+02:00
tl;dr
- Use modern java.time classes as much as possible, rather than the terrible legacy classes.
- Always specify your desired/expected time zone or offset-from-UTC rather than rely implicitly on JVM’s current default.
Example code (without exception-handling):
XMLGregorianCalendar xgc =
DatatypeFactory // Data-type converter.
.newInstance() // Instantiate a converter object.
.newXMLGregorianCalendar( // Converter going from `GregorianCalendar` to `XMLGregorianCalendar`.
GregorianCalendar.from( // Convert from modern `ZonedDateTime` class to legacy `GregorianCalendar` class.
LocalDate // Modern class for representing a date-only, without time-of-day and without time zone.
.parse( "2014-01-07" ) // Parsing strings in standard ISO 8601 format is handled by default, with no need for custom formatting pattern.
.atStartOfDay( ZoneOffset.UTC ) // Determine the first moment of the day as seen in UTC. Returns a `ZonedDateTime` object.
) // Returns a `GregorianCalendar` object.
) // Returns a `XMLGregorianCalendar` object.
;
Parsing date-only input string into an object of XMLGregorianCalendar
class
Avoid the terrible legacy date-time classes whenever possible, such as XMLGregorianCalendar
, GregorianCalendar
, Calendar
, and Date
. Use only modern java.time classes.
When presented with a string such as "2014-01-07"
, parse as a LocalDate
.
LocalDate.parse( "2014-01-07" )
To get a date with time-of-day, assuming you want the first moment of the day, specify a time zone. Let java.time determine the first moment of the day, as it is not always 00:00:00.0 in some zones on some dates.
LocalDate.parse( "2014-01-07" )
.atStartOfDay( ZoneId.of( "America/Montreal" ) )
This returns a ZonedDateTime
object.
ZonedDateTime zdt =
LocalDate
.parse( "2014-01-07" )
.atStartOfDay( ZoneId.of( "America/Montreal" ) )
;
zdt.toString() = 2014-01-07T00:00-05:00[America/Montreal]
But apparently, you want the start-of-day as seen in UTC (an offset of zero hours-minutes-seconds). So we specify ZoneOffset.UTC
constant as our ZoneId
argument.
ZonedDateTime zdt =
LocalDate
.parse( "2014-01-07" )
.atStartOfDay( ZoneOffset.UTC )
;
zdt.toString() = 2014-01-07T00:00Z
The Z
on the end means UTC (an offset of zero), and is pronounced “Zulu”.
If you must work with legacy classes, convert to GregorianCalendar
, a subclass of Calendar
.
GregorianCalendar gc = GregorianCalendar.from( zdt ) ;
gc.toString() = java.util.GregorianCalendar[time=1389052800000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2014,MONTH=0,WEEK_OF_YEAR=2,WEEK_OF_MONTH=2,DAY_OF_MONTH=7,DAY_OF_YEAR=7,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=0,DST_OFFSET=0]
Apparently, you really need an object of the legacy class XMLGregorianCalendar
. If the calling code cannot be updated to use java.time, convert.
XMLGregorianCalendar xgc =
DatatypeFactory
.newInstance()
.newXMLGregorianCalendar( gc )
;
Actually, that code requires a try-catch.
try
{
XMLGregorianCalendar xgc =
DatatypeFactory
.newInstance()
.newXMLGregorianCalendar( gc );
}
catch ( DatatypeConfigurationException e )
{
e.printStackTrace();
}
xgc = 2014-01-07T00:00:00.000Z
Putting that all together, with appropriate exception-handling.
// Given an input string such as "2014-01-07", return a `XMLGregorianCalendar` object
// representing first moment of the day on that date as seen in UTC.
static public XMLGregorianCalendar getXMLGregorianCalendar ( String input )
{
Objects.requireNonNull( input );
if( input.isBlank() ) { throw new IllegalArgumentException( "Received empty/blank input string for date argument. Message # 11818896-7412-49ba-8f8f-9b3053690c5d." ) ; }
XMLGregorianCalendar xgc = null;
ZonedDateTime zdt = null;
try
{
zdt =
LocalDate
.parse( input )
.atStartOfDay( ZoneOffset.UTC );
}
catch ( DateTimeParseException e )
{
throw new IllegalArgumentException( "Faulty input string for date does not comply with standard ISO 8601 format. Message # 568db0ef-d6bf-41c9-8228-cc3516558e68." );
}
GregorianCalendar gc = GregorianCalendar.from( zdt );
try
{
xgc =
DatatypeFactory
.newInstance()
.newXMLGregorianCalendar( gc );
}
catch ( DatatypeConfigurationException e )
{
e.printStackTrace();
}
Objects.requireNonNull( xgc );
return xgc ;
}
Usage.
String input = "2014-01-07";
XMLGregorianCalendar xgc = App.getXMLGregorianCalendar( input );
Dump to console.
System.out.println( "xgc = " + xgc );
xgc = 2014-01-07T00:00:00.000Z
Modern date-time classes versus legacy
Date-time != String
Do not conflate a date-time value with its textual representation. We parse strings to get a date-time object, and we ask the date-time object to generate a string to represent its value. The date-time object has no ‘format’, only strings have a format.
So shift your thinking into two separate modes: model and presentation. Determine the date-value you have in mind, applying appropriate time zone, as the model. When you need to display that value, generate a string in a particular format as expected by the user.
Avoid legacy date-time classes
The Question and other Answers all use old troublesome date-time classes now supplanted by the java.time classes.
ISO 8601
Your input string "2014-01-07"
is in standard ISO 8601 format.
The T
in the middle separates date portion from time portion.
The Z
on the end is short for Zulu and means UTC.
Fortunately, the java.time classes use the ISO 8601 formats by default when parsing/generating strings. So no need to specify a formatting pattern.
LocalDate
The LocalDate
class represents a date-only value without time-of-day and without time zone.
LocalDate ld = LocalDate.parse( "2014-01-07" ) ;
ld.toString(): 2014-01-07
Start of day ZonedDateTime
If you want to see the first moment of that day, specify a ZoneId
time zone to get a moment on the timeline, a ZonedDateTime
. The time zone is crucial because the date varies around the globe by zone. A few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
Never assume the day begins at 00:00:00. Anomalies such as Daylight Saving Time (DST) means the day may begin at another time-of-day such as 01:00:00. Let java.time determine the first moment.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z ) ;
zdt.toString(): 2014-01-07T00:00:00Z
For your desired format, generate a string using the predefined formatter DateTimeFormatter.ISO_LOCAL_DATE_TIME
and then replace the T
in the middle with a SPACE.
String output = zdt.format( DateTimeFormatter.ISO_LOCAL_DATE_TIME )
.replace( "T" , " " ) ;
2014-01-07 00:00:00
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
- Java SE 8, Java SE 9, and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
- See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
For me the most elegant solution is this one:
XMLGregorianCalendar result = DatatypeFactory.newInstance()
.newXMLGregorianCalendar("2014-01-07");
Using Java 8.
Extended example:
XMLGregorianCalendar result = DatatypeFactory.newInstance()
.newXMLGregorianCalendar("2014-01-07");
System.out.println(result.getDay());
System.out.println(result.getMonth());
System.out.println(result.getYear());
This prints out:
7
1
2014