[ACCEPTED]-How to handle jodatime Illegal instant due to time zone offset transition-jodatime

Accepted answer
Score: 37

It seems like you're trying to get from 13 a specific local time to a DateTime instance and 12 you want that to be robust against daylight 11 savings. Try this... (note I'm in US/Eastern, so 10 our transition date was 13 Mar 11; I had 9 to find the right date to get the exception 8 you got today. Updated my code below for 7 CET, which transitions today.) The insight 6 here is that Joda provides LocalDateTime to let you reason 5 about a local wall-clock setting and whether 4 it's legal in your timezone or not. In 3 this case, I just add an hour if the time 2 doesn't exist (your application has to decide 1 if this is the right policy.)

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;

class TestTz {

  public static void main(String[] args)
  {
     final DateTimeZone dtz = DateTimeZone.forID("CET");
     LocalDateTime ldt = new LocalDateTime(dtz)
       .withYear(2011)
       .withMonthOfYear(3)
       .withDayOfMonth(27)
       .withHourOfDay(2);

    // this is just here to illustrate I'm solving the problem; 
    // don't need in operational code
    try {
      DateTime myDateBorken = ldt.toDateTime(dtz);
    } catch (IllegalArgumentException iae) {
      System.out.println("Sure enough, invalid instant due to time zone offset transition!");
    }

    if (dtz.isLocalDateTimeGap(ldt)) {
      ldt = ldt.withHourOfDay(3);
    }

    DateTime myDate = ldt.toDateTime(dtz);
    System.out.println("No problem: "+myDate);
  }

}

This code produces:

Sure enough, invalid instant due to time zone offset transition!
No problem: 2011-03-27T03:00:00.000+02:00
Score: 13

CET switches to DST (summer time) on the last 5 Sunday in March, which happens to be today. The 4 time went from 1:59:59 to 3:00:00 – there's 3 no 2, hence the exception.

You should use 2 UTC instead of local time to avoid this 1 kind of time zone issue.

MutableDateTime now = new MutableDateTime(DateTimeZone.UTC);
Score: 8

I think a lot of the time, you will want 25 joda to fix this automatically for you. You 24 will often not know the correct way to fix 23 a gap date because the size of the gap depends 22 on the zone and the year (although of course 21 it's usually an hour).

One example of this 20 is if you are parsing a timestamp that comes 19 from a source you don't control; eg, the 18 network. If the sender of the timestamp 17 has outdated zone files, this could happen. (If 16 you have outdated zone files, you're pretty 15 much screwed).

Here's a way to do that, which, granted, is 14 slightly more complicated. I've made it 13 work in joda 1.6 as well as 2.x, since we 12 happen to be stuck on 1.6 in our environment.

If 11 you're building a date from some other inputs 10 as in your question, you can start with 9 a UTC date or a LocalDate as suggested above, and 8 then adapt this to automatically fix your 7 offset. The special sauce is in DateTimeZone.convertLocalToUTC

Dangerous:

public DateTime parse(String str) {
    formatter.parseDateTime(gapdate)
}

Safe:

public DateTime parse(String str) {
    // separate date from zone; you may need to adjust the pattern,
    // depending on what input formats you support
    String[] parts = str.split("(?=[-+])");
    String datepart = parts[0];
    DateTimeZone zone = (parts.length == 2) ?
        DateTimeZone.forID(parts[1]) : formatter.getZone();

    // parsing in utc is safe, there are no gaps
    // parsing a LocalDate would also be appropriate, 
    // but joda 1.6 doesn't support that
    DateTime utc = formatter.withZone(DateTimeZone.UTC).parseDateTime(datepart);

    // false means don't be strict, joda will nudge the result forward by the
    // size of the gap.  The method is somewhat confusingly named, we're
    // actually going from UTC to local
    long millis = zone.convertLocalToUTC(utc.getMillis(), false);

    return new DateTime(millis, zone);
}

I've 6 tested this in the eastern and western hemispheres 5 as well as the Lord Howe Island zone, which 4 happens to have a half hour dst.

It would 3 be kind of nice if joda formatters would 2 support a setStrict(boolean) that would 1 have them take care of this for you...

Score: 3

If you need to parse date from string:

final DateTimeZone dtz = DateTimeZone.getDefault(); //DateTimeZone.forID("Europe/Warsaw")
LocalDateTime ldt = new LocalDateTime("1946-04-14", dtz);
if (dtz.isLocalDateTimeGap(ldt)){
    ldt = ldt.plusHours(1);
}
DateTime date = ldt.toDateTime();
Date date = date.toDate();

Worked 2 for me perfectly. Maybe somebody will need 1 it.

Score: 0

Update to jodatime 2.1 and use LocalDate.parse():

DateTimeFormatter formatter = DateTimeFormat.forPattern("dd/MM/yyyy");
LocalDate.parse(date, formatter);

0

More Related questions