Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing date with Joda with time zone

I have two timestamps which describe the same instant of time in two different formats.

2010-10-03 18:58:07 and 2010-10-03T16:58:07.000+02:00.

I parse the timestamps with two different date formatters with Joda-Time. In the end I want to have two DateTime objects that are equal in terms of being the same instant of time.

The DateFormatter offers several methods to control time zones and locales but i couldn't get it to work.

This is the code that i would like to work:

    final String date1 = "2010-10-03 18:58:07"; // Europe/Berlin local time
    final DateTimeFormatter formatter1 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
    final DateTime dateTime1 = formatter1.parseDateTime(date1);

    final String date2 = "2010-10-03T16:58:07.000+02:00"; // Europe/Berlin local time with time zone
    final DateTimeFormatter formatter2 = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    final DateTime dateTime2 = formatter2.parseDateTime(date2);

    Assert.assertTrue(dateTime1.isEqual(dateTime2));
like image 363
wilfried Avatar asked Jan 07 '11 11:01

wilfried


People also ask

Does Joda datetime have TimeZone?

An interval in Joda-Time represents an interval of time from one instant to another instant. Both instants are fully specified instants in the datetime continuum, complete with time zone.

How do I change the TimeZone in Joda datetime?

forPattern("yyyy-MM-dd")). withZoneRetainFields(DateTimeZone. forID("PST")); // it will change timezone to PST but not the actual date field value.

What is Joda-time format?

Joda-Time provides a comprehensive formatting system. There are two layers: High level - pre-packaged constant formatters. Mid level - pattern-based, like SimpleDateFormat.

Is Joda-time deprecated?

So the short answer to your question is: YES (deprecated).


3 Answers

If your default time zome is Europe/Berlin, 2010-10-03 18:58:07 corresponds to 2010-10-03T16:58:07.000+00:00.

You probably misunderstand the time zone field in the string representation. Your time stamp 2010-10-03T16:58:07.000+02:00 means that "it is 16:58:07 in a time zone with a +2 hour offset from GMT), or in an other wording "it is now 16:58:07 in Berlin". I assume that you expected it to mean that it's 16:58:07 GMT?

like image 71
jarnbjo Avatar answered Oct 14 '22 09:10

jarnbjo


Your two timestamps don't represent the same instant in time (as jambjo already remarked). See Time zone as offsets from UTC on wikipedia.

Also see the parseDateTime documentation on how it works. If you don't provide any time zone, then the default time zone will be applied (that is Berlin time zone UTC+2 if you are there). So:

  • 2010-10-03 18:58:07 becomes 2010-10-03T18:58:07.000+02:00 (18:58 in Berlin with offset of 2 hours to UTC, that means 16:58 in UTC) as expected.
  • 2010-10-03T16:58:07.000+02:00 stays as it is, because there is a time zone provided (i.e. 16:58 in Berlin with offset of 2 hours to UTC, that means 14:58 in UTC)

Hope you got the idea. You will need to adjust the times with the withZone method to get the desired results.

like image 45
MicSim Avatar answered Oct 14 '22 11:10

MicSim


tl;dr

Use the modern java.time classes that supplanted Joda-Time.

LocalDateTime                                   // Represent a date and time-of-day without the context of a time zone or offset-from-UTC. *Not* a moment, *not* a point on the timeline.
.parse(                                         // Parse text into a date-time value.
    "2010-10-03 18:58:07".replace( " " , "T" )  // Replace SPACE in middle with a `T` to comply with ISO 8601 standard used by default in *java.time* when parsing/generating strings.
)                                               // Returns a `LocalDateTime` object.
.atZone(                                        // Assign the time zone we know for certain was intended for this input. 
    ZoneId.of( "Europe/Moscow" )                // Real time zones are named in `Continent/Region` format, never 2-4 letter codes such as CST, PST, IST, CEST, etc.
)                                               // Returns a `ZonedDateTime` object, a date with time-of-day and with a time zone assigned to determine a moment.
.toInstant()                                    // Adjust from time zone to UTC. 
.equals(
    OffsetDateTime                              // Represent a date and time-of-day with an offset-from-UTC but not a full time zone.
    .parse( "2010-10-03T16:58:07.000+02:00" )   // Parse a standard ISO 8601 string.
    .toInstant()                                // Adjust from offset to UTC (in other words, an offset of zero hours-minutes-seconds). 
)                                               // Returns `boolean`. 

true

Details

The Answer by jarnbjo is correct in that you misunderstood the meanings of the offset-from-UTC and time zone values.

Now in 2018, the Joda-Time project is in maintenance-mode. That project’s principal author, Stephen Colebourne, went on to found JSR 310 and author its implementation, the java.time classes found in OpenJDK.

First input

Your input string 2010-10-03 18:58:07 is nearly in standard ISO 8601 format. To comply, replace the SPACE in the middle with a T.

String input1 = "2010-10-03 18:58:07".replace( " " , "T" ) ;

That string lacks any indicator of time zone or offset-from-UTC. So parse as a LocalDateTime.

LocalDateTime ldt = LocalDateTime.parse( input1 ) ;

This value does not represent a moment, is not a point on the timeline. Without the context of a zone or offset, it could be any of many moments within a range of about 26-27 hours, the range of time zones around the globe.

In your comments you revealed that apparently that input string was meant to represent a date and time-of-day in the Europe/Moscow time zone. So we can assign that zone to determine a moment, a point on the timeline.

ZoneId zMoscow = ZoneId.of( "Europe/Moscow" ) ;
ZonedDateTime zdtMoscow = ldt.atZone( zMoscow ) ;  // Determine a moment by assigning a time zone.

zdtMoscow.toString(): 2010-10-03T18:58:07+04:00[Europe/Moscow]

Second input

Your second input 2010-10-03T16:58:07.000+02:00complies with standard ISO 8601 format.

This input carries an offset-from-UTC of two hours ahead of UTC. So this string represents the time-of-day of 14:58:07 in UTC.

We can parse as a OffsetDateTime to respect the given offset.

OffsetDateTime odt2 = OffsetDateTime.parse( "2010-10-03T16:58:07.000+02:00" ) ;

odt2.toString(): 2010-10-03T16:58:07+02:00

Compare

Do these two inputs represent the same moment, the same point on the timeline?

One way to compare is by adjusting both to UTC. An Instant is always in UTC, by definition.

Tip: Get in the habit of thinking, working, storing, exchanging, and logging in UTC. Think of UTC as The One True Time.

Instant instant1 = zdtMoscow.toInstant() ;  // Adjust from time zone to UTC.
Instant instant2 = odt2.toInstant() ;       // Adjust from offset to UTC.

boolean equality = instant1.equals( instant2 );

When run, we see results with a Z on the end. That means UTC, and is pronounced Zulu. And, indeed, we see these two values represent the same moment, almost 3 PM in UTC.

instant1.toString(): 2010-10-03T14:58:07Z

instant2.toString(): 2010-10-03T14:58:07Z

equality: true


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?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - 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
    • Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). 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.

like image 24
Basil Bourque Avatar answered Oct 14 '22 09:10

Basil Bourque