I am trying to convert a DateTime value retrieved from Windows Management Interface into a Java (1.7) Date. The format is specified here.
An example that I am trying to parse is
SimpleDateFormat cimDateFormat = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
Date date = cimDateFormat.parse(s, new ParsePosition(0));
SimpleDateFormat cimDateFormat = new SimpleDateFormat("yyyyMMddHHmmss.S");
Date date = cimDateFormat.parse(s.substring(0, 18), new ParsePosition(0));
As far as I know, none of the three common date-time frameworks for Java (the old bundled java.util.Date/.Calendar/java.text.SimpleDateFormat classes, the Joda-Time framework, or the java.time framework built into Java 8 and later) allow for an offset-from-UTC as a total number of minutes.
As suggested by Sotirios Delimanolis, you must modify the offset-from-UTC to convert from a number of total minutes to the standard number of hours and minutes (and seconds – a possibility ignored by that odd Microsoft format). So
-420 should become
You are using the troublesome old date-time classes bundled with the earliest versions of Java. The old classes are now legacy, and have been supplanted by the java.time framework built into Java 8 and later, and largely back-ported to Java 6 & 7 and further adapted to Android.
The java.time classes have a resolution of nanoseconds, for up to nine digits of a decimal fraction of second. So no problem handling your inputs 4-6 digits of fractional second.
Our strategy has two parts: (a) Modify the input to convert that offset-from-UTC, and (b) Parse the modified input string as a date-time object.
First we change the input from
20160513072950.782000-07:00:00. We do this by extracting the characters trailing after the
420 in this case.
// Modify the input to replace offset as a number of minutes to the standard format, a number of hours, minutes, and seconds. String input = "20160513072950.782000-420"; String offsetInMinutesAsString = input.substring ( 22 );
Convert that to a
long, and create a
LocalTime object so that we can generate a string in the format of
long offsetInMinutes = Long.parseLong ( offsetInMinutesAsString ); LocalTime offsetAsLocalTime = LocalTime.MIN.plusMinutes ( offsetInMinutes ); String offsetAsString = offsetAsLocalTime.format ( DateTimeFormatter.ISO_LOCAL_TIME );
Replace those trailing characters with our generated string.
String inputModified = ( input.substring ( 0 , 22 ) + offsetAsString );
// Parse the modified input as an OffsetDateTime. DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "yyyyMMddHHmmss.SSSSSSZZZZZ" , Locale.US ); OffsetDateTime odt = OffsetDateTime.parse ( inputModified , formatter );
Dump to console.
System.out.println ( "input: " + input + " | inputModified: " + inputModified + " | odt: " + odt );
input: 20160513072950.782000-420 | inputModified: 20160513072950.782000-07:00:00 | odt: 2016-05-13T07:29:50.782-07:00
I strongly suggest avoiding the old date-time classes. But if you must use a
java.util.Date object to interoperate with old date-time code, you can convert.
Look for new methods added to the old classes for conversion. For this conversion we use
java.util.Date.from. We need to feed that conversion method a
Instant object, a moment on the timeline in UTC with a resolution of nanoseconds. We can extract one from our
Instant instant = odt.toInstant(); java.util.Date utilDate = java.util.Date.from( instant );
For more info about converting, including a nifty diagram, see my Answer to another Question. Keep in mind that we are working with only a mere offset-from-UTC in our input strings and our
OffsetDateTime, not a full time zone. A time zone is an offset plus rules for handling anomalies such as Daylight Saving Time (DST). Both the
Instant and the
java.util.Date are in UTC (an offset of zero).