Search code examples
javadatetimetimezonejodatimelocaltime

Timezone issue with Joda-time when converting a LocalTime to a DateTime using .toDateTime()


I am writing some code to do periodic scheduling based based on time of day. I am representing the regular schedule time of day as a Joda LocalTime object. I then create event instances by converting the LocalTime to a DateTime. When initially writing the code (and only scheduling events for "today") I used the toDateTimeToday() method on LocalTime and it worked as expected. However when I switched to using the toDateTime() method to schedule events in the future I started seeing issues with mapping between UTC and local local timezone.

The following code demonstrates the problem I am seeing.

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

LocalTime lt = new LocalTime(12,0);
System.out.println(" lt="+lt);

DateTime dtt = lt.toDateTimeToday();
System.out.println("dtt="+df.format(dtt.toDate()));

DateTime bdt = new DateTime();
System.out.println("bdt="+df.format(bdt.toDate()));

DateTime dt = lt.toDateTime(bdt.toInstant());
System.out.println(" dt="+df.format(dt.toDate()));

Here is the output:

 lt=12:00:00.000
dtt=2014-07-08T12:00:00-0400
bdt=2014-07-08T18:01:30-0400
 dt=2014-07-08T08:00:00-0400

As you can see, the dtt and dt should be the same time, but they are different by the local timezone offset.

UPDATE

Based on Matt Johnson's answer, I made a simple change in my code, replacing:

DateTime dt = lt.toDateTime(bdt.toInstant());

with

DateTime dt = new LocalDate(bdt).toDateTime(lt); 

My code updated with the change (plus switching to Joda formatting) is as follows:

DateTimeZone.setDefault(DateTimeZone.forTimeZone(TimeZone.getDefault()));

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ");

LocalTime lt = new LocalTime(12,0);
System.out.println(" lt="+lt);

DateTime dtt = lt.toDateTimeToday();
System.out.println("dtt="+dtt.toString(fmt));

DateTime bdt = new DateTime();
System.out.println("bdt="+bdt.toString(fmt));

DateTime dt = new LocalDate(bdt).toDateTime(lt);
System.out.println(" dt="+dt.toString(fmt));

Here's the new (correct!!) output.

 lt=12:00:00.000
dtt=2014-07-09T12:00:00-0400
bdt=2014-07-09T00:15:35-0400
 dt=2014-07-09T12:00:00-0400

Thanks Matt!


Solution

  • Consider:

    LocalTime lt = new LocalTime(12, 0);        // the scheduled time
    LocalDate ld = new LocalDate(2014, 7, 8);   // the day to run
    
    DateTime dt = ld.ToDateTime(lt);
    

    The above code will use the default time zone. If your event is scheduled to run in a particular time zone, use:

    DateTimeZone tz = DateTimeZone.forID("America/New_York");
    DateTime dt = ld.ToDateTime(lt, tz);