I\'m trying to convert my String
in Date
+ Timezone.
I get my String from a DateTime
Variable (here: xyz).
My code:
Strin
The input has a date - year, month, day - and an offset - the difference from UTC - but to build a java.util.Date
, you also need the time: hour, minutes, seconds, fraction of seconds.
SimpleDateFormat
is terrible because it does some "magic", setting the missing fields to default values. Another problem is that the X
pattern doesn't work for all Java versions, and the documentation sucks.
You can use the new Java 8 classes, as explained. With them, you can parse the input, choose the default values to be used for the time fields and convert to java.util.Date
, if that's what you need:
DateTimeFormatter fmt = new DateTimeFormatterBuilder().append(DateTimeFormatter.ISO_OFFSET_DATE)
// set hour to midnight
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0).toFormatter();
OffsetDateTime odt = OffsetDateTime.parse("2017-01-03+01:00", fmt); // 2017-01-03T00:00+01:00
The OffsetDateTime
will have the time set to midnight, but you can change it to whatever values you need, while with SimpleDateFormat
it's not possible, because it uses internal default values and you can't control it.
And the date and offset were correctly set to the values in the input string. You can then convert to java.util.Date
if you want:
Date date = Date.from(odt.toInstant());
You can also get the individual "pieces" of the date if you want:
// get just the date
LocalDate localDate = odt.toLocalDate(); // 2017-01-03
// get just the offset
ZoneOffset offset = odt.getOffset(); // +01:00
PS: the offset +01:00
is not the same thing as a timezone. See the difference here
String abc = "2017-01-03+01:00";
TemporalAccessor parsed = DateTimeFormatter.ISO_OFFSET_DATE.parse(abc);
LocalDate date = LocalDate.from(parsed);
ZoneOffset offset = ZoneOffset.from(parsed);
System.out.println("Date: " + date + "; offset: " + offset + '.');
This prints:
Date: 2017-01-03; offset: +01:00.
I am using java.time
, the modern Java date and time API, and recommend you do the same. The Date
class is long outdated (sorry, no pun intended) and SimpleDateFormat
in particular notoriously troublesome. Don’t use them. The modern API is so much nicer to work with. Only if you need a java.util.Date
and/or a java.util.TimeZone
for a legacy API that you cannot change, convert like this:
Date oldfashionedDate = Date.from(date.atStartOfDay(offset).toInstant());
TimeZone oldfashionedTimeZone = TimeZone.getTimeZone(offset);
System.out.println("Old-fashioned date: " + oldfashionedDate
+ "; old-fashioned time-zone: " + oldfashionedTimeZone.getDisplayName() + '.');
On my computer this prints:
Old-fashioned date: Tue Jan 03 00:00:00 CET 2017; old-fashioned time-zone: GMT+01:00.
I happen to be in a time zone that agrees with your offset from UTC, so it’s fairly obvious that the conversion has given the correct result. In other time zones the output will be more confusing because Date.toString()
uses the JVM’s time zone setting for generating the string, but the Date
will still be correct.
A date with a time zone? Neither a LocalDate
nor a Date
can hold a time zone in them, so you need to have the offset information separately. Interestingly your string seems to follow a “ISO-8601-like” format for an offset date that is even represented by a built-in formatter that has ISO in its name. If Java had contained an OffsetDate
or a ZonedDate
class, I would have expected such a class to parse your string into just one object and even without an explicit formatter. Unfortunately no such class exists, not even in the ThreeTen-Extra project, as far as I can tell at a glance.
Links
java.time
.java.time
."2017-01-03+01:00"
I thought it a similar ISO 8601 format date string, but actually not ISO 8601. Thanks @Meno Hochschild and @Basil Bourque's indication.
It is so luck that this method works for such format's string: javax.xml.bind.DatatypeConverter.parseDateTime
, it will return a Calendar
:
System.out.println(DatatypeConverter.parseDate("2017-01-03+01:00").getTime());
Output:
Tue Jan 03 07:00:00 CST 2017
From the method javadoc:
public static Calendar parseDate(String lexicalXSDDate)
Converts the string argument into a Calendar value.
Parameters: lexicalXSDDate - A string containing lexical representation of xsd:Date.
Returns: A Calendar value represented by the string argument.
Throws: IllegalArgumentException - if string parameter does not conform to lexical value space defined in XML Schema Part 2: Datatypes for xsd:Date.