20

I am trying to serialize/deserialize a date from/to a JavaScript application.

Server side, I use Java, JodaTime is installed on it. I found out how to serialize to ISO with UTC Time zone, but can't find out how to do the reverse operation.

Here is my code

public static String getIsoDate( Date date )
{
    SimpleDateFormat  dateToIsoDateString = new SimpleDateFormat( ISO_8601_DATE_FORMAT );
    TimeZone tz = TimeZone.getTimeZone("UTC");
    dateToIsoDateString.setTimeZone( tz );
    return dateToIsoDateString.format( date );
}

// this will return a date with GMT timezone
public static Date getDateFromIsoDateString( String iso8601date )
{
    DateTimeFormatter jodaParser = ISODateTimeFormat.dateTimeNoMillis();
    return jodaParser.parseDateTime( iso8601date ).toDate();
}

I don't mind using or not Joda, just need a quick and working solution,

halfer
  • 19,824
  • 17
  • 99
  • 186
Dimitri Kopriwa
  • 13,139
  • 27
  • 98
  • 204
  • possible duplicate of [Converting ISO 8601-compliant String to java.util.Date](http://stackoverflow.com/questions/2201925/converting-iso-8601-compliant-string-to-java-util-date) – Basil Bourque Sep 19 '14 at 17:07
  • Your question is not clear. You should provide samples of inputs and desired outputs. – Basil Bourque Sep 19 '14 at 17:31

4 Answers4

33

If you are using Java 7 or earlier you can refer to this post.

If you are using Java 8 you could do:

    DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
    TemporalAccessor accessor = timeFormatter.parse("2015-10-27T16:22:27.605-07:00");

    Date date = Date.from(Instant.from(accessor));
    System.out.println(date);

Update

As pointed out by @BasilBourque in the comment, TemporalAccessor is java framework level interface, and is not advisable to use in the application code and it is advisable to use concrete classes rather than the interfaces.

This interface is a framework-level interface that should not be widely used in application code. Instead, applications should create and pass around instances of concrete types, such as LocalDate. There are many reasons for this, part of which is that implementations of this interface may be in calendar systems other than ISO. See ChronoLocalDate for a fuller discussion of the issues.

There a few concrete classes available to use, like LocalDate, LocalDateTime, OffsetDateTime, ZonedDateTime and etc..

DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;

OffsetDateTime offsetDateTime = OffsetDateTime.parse("2015-10-27T16:22:27.605-07:00", timeFormatter);

Date date = Date.from(Instant.from(offsetDateTime));
System.out.println(date);
always_a_rookie
  • 4,515
  • 1
  • 25
  • 46
  • The *java.time* classes discourage using the interfaces/superclasses. The concrete class `OffsetDateTime` class is appropriate here. `OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" )` – Basil Bourque Jun 07 '18 at 20:56
  • @BasilBourque You are right. The documentation suggests not to use the framework-level interfaces in the application code. Updated the answer. – always_a_rookie Jun 08 '18 at 18:19
18

tl;dr

OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" )
.toInstant()
.toString()

2015-10-27T23:22:27.605Z

Details

Your question is not clear and specific. Perhaps these little examples will help. Mixing the old java.util.Date and .Calendar classes with Joda-Time may be confusing you. Joda-Time completely replaces those classes rather than augments.

java.time

The modern java.time classes supplant both the legacy date-time classes in Java as well as the Joda-Time library which provided their inspiration.

OffsetDateTime

The OffsetDateTime class represents a moment on the timeline with a particular offset-from-UTC determining its wall-clock time.

The java.time classes use the standard ISO 8601 formats by default when parsing/generating strings. So no need to specify a formatting pattern.

OffsetDateTime odt = OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" ) ;

Instant

To adjust from the offset of seven hours behind UTC to UTC itself, we need to add seven hours to the time-of-day and rollover the date if need be. The OffsetDateTime class can do this work for us. Specify UTC using the ZoneOffset.UTC constant.

OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;

odtUtc.toString(): 2015-10-27T23:22:27.605Z

If you are using this UTC value much in your code, and generally you should be, then you may find it more clear to use Instant objects. An Instant is always in UTC by definition. We can extract an Instant from the OffsetDateTime.

Instant instant = odt.toInstant() ;

instant.toString(): 2015-10-27T23:22:27.605Z

Note that all three of our objects above (odt, odtUtc, instant) all represent the very same simultaneous moment, the same point on the timeline. The only thing different is their wall-clock time.

ZonedDateTime

By the way, if you want to see that same moment adjusted to the wall-clock time in use by the people of a certain region, specify a time zone via ZoneId to get a ZonedDateTime object.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

zdt.toString(): 2015-10-27T19:22:27.605-04:00[America/Montreal]

Use concrete classes in java.time

The Answer by always_a_rookie_to_learn is similar to the above approach but uses the interface TemporalAccessor. Generally, using the higher interfaces and superclasses is a good idea in Java. But not here. The java.time documentation explains that their design intends us to use the lower more concrete classes in our apps. The abstractions are for internal use only within the framework, generally.

In the specific case of this Question, the class OffsetDateTime is appropriate rather than TemporalAccessor.


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.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

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.


Joda-Time

UPDATE: The Joda-Time project in is maintenance mode, and it advises migration to the java.time classes. This section is left intact for history.

Joda-Time defaults to ISO 8601 for strings, both parsing and generating. Joda-Time has built-in default parsers for ISO 8601, so simply pass your compliant string to the constructor or to the static parse method.

java.util.Date date = new DateTime( "2010-01-01T12:00:00+01:00Z" ).toDate();

When possible, avoid java.util.Date and .Calendar, and stick with Joda-Time and it's classes such as DateTime. Use .Date only where required by other classes.

DateTime dateTimeUtc = new DateTime( someJavaDotUtilDotDate, DateTimeZone.UTC ); // Joda-Time can convert from java.util.Date type which has no time zone.
String output = dateTime.toString(); // Defaults to ISO 8601 format.
DateTime dateTimeUtc2 = new DateTime( output, DateTimeZone.UTC ); // Joda-Time can parse ISO 8601 strings.

For presentation, adjust to time zone expected by the user.

DateTime dateTimeMontréal = dateTimeUtc.withZone( DateTimeZone.forID( "America/Montreal" ) );
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
2

Native solution in Java8

Date.from(ZonedDateTime.parse("1994-11-05T08:15:30+05:30").toInstant())

Date.from(ZonedDateTime.parse("1994-11-05T13:15:30Z").toInstant())
Mangu
  • 3,160
  • 2
  • 25
  • 42
stonelazy
  • 480
  • 5
  • 9
  • `ZonedDateTime` is not the appropriate class to be using here. For the first, use `OffsetDateTime.parse`. For the second, `Instant.parse`. As I had already posted in [my Answer](https://stackoverflow.com/a/25939190/642706). – Basil Bourque Oct 01 '18 at 16:46
  • 1
    But, According to https://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html "A date-time with a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00 Europe/Paris." ZonedDateTime is also a valid solution I hope, is it not ? I get the same output for both methods. – stonelazy Oct 03 '18 at 06:13
  • 3
    Notice the name of the official time zone in that quote, `Europe/Paris`. Our input string under discussion lacks that time zone and has only an offset-from-UTC. An offset is merely a number of hours, minutes, seconds. A time zone is much more, a history of past, present, and future changes to the offset used by the people of a particular region. Your code worked because *java.time* is implemented with `ZoneOffset` as a subclass of `ZoneId`. The code works but is misleading, suggesting a time zone is in play when actually we have no zone at all. Read about `OffsetDateTime` class. – Basil Bourque Oct 03 '18 at 06:30
2

If your date is in ISO 8601 UTC format (Example: 2022-06-04T10:50:27Z) then you can use Instant directly to parse it:

Instant.parse("2022-06-04T10:50:27Z")

vovahost
  • 34,185
  • 17
  • 113
  • 116