3

I have a little utility method which converts a DateTime to a specific DateTimeZone, sets the time in that time zone and converts to another timezone again:

/**
 * Delivers a DateTime with changed time in the specified DateTimeZone.
 *
 * @param  dateTime      the date time to convert
 * @param  hour          the hour to set in the client timezone date time
 * @param  minute        the minute to set in the client timezone date time
 * @param  second        the second to set in the client timezone date time
 * @param  dtzConversion the client time zone
 * @param  dtzReturn     the time zone of the return date time (optionally: can be null)
 * @return the date time
 */
public DateTime convertDateTimeToTimeZone(final DateTime dateTime, final int hour, final int minute, final int second,
                                          final DateTimeZone dtzConversion, final DateTimeZone dtzReturn)
{
    // convert to given timezone        
    DateTime dtClientTimezone = dateTime.withZoneRetainFields(dtzConversion);
    // adjust time
    dtClientTimezone = dtClientTimezone.withTime(hour, minute, second, 0);

    if (dtzReturn != null) {
        // convert to target timezone
        dtClientTimezone = dtClientTimezone.withZoneRetainFields(dtzReturn);
    }

    return dtClientTimezone;
}

In my example dateTime is the german date 30.9.2015 22:00:00 UTC and dtzConversion is Europe/Berlin and dtzReturn is UTC with time to set 12:00:00 the result is 30.09.2015 12:00:00. But I would expect the 01.10.2015 10:00:00 because 30.09.2015 22:00:00 UTC to Europe/Berlin should be 01.10.2015 00:00:00. The the time is set to '12:00:00' which results in 01.10.2015 12:00:00. This in UTC is 01.10.2015 10:00:00. Where is my fault?

opfau
  • 731
  • 9
  • 37

1 Answers1

4

The method withZoneRetainFields does not convert the fields values. Instead, it just changes the timezone (and the underlying milliseconds so that the fields have the same values in the new timezone as in the old one).

The method you are searching for is withZone, which adjusts the fields:

public static DateTime convertDateTimeToTimeZone(final DateTime dateTime, final int hour, final int minute,
        final int second,
        final DateTimeZone dtzConversion, final DateTimeZone dtzReturn)
{
    // convert to given timezone        
    DateTime dtClientTimezone = dateTime.withZone(dtzConversion);
    // adjust time
    dtClientTimezone = dtClientTimezone.withTime(hour, minute, second, 0);

    if (dtzReturn != null) {
        // convert to target timezone
        dtClientTimezone = dtClientTimezone.withZone(dtzReturn);
    }

    return dtClientTimezone;
}

public static void main(String[] args)
{
    DateTime parse = DateTime.parse("2015-09-30T22:00:00Z");
    DateTime convertDateTimeToTimeZone = convertDateTimeToTimeZone(parse, 12, 0, 0, DateTimeZone.forOffsetHours(2), DateTimeZone.UTC);
    System.out.println(convertDateTimeToTimeZone);
}

Result:

2015-10-01T10:00:00.000Z

flo
  • 9,713
  • 6
  • 25
  • 41
  • Seems right. But why the first timezone conversion the time millis are the same? `DateTime dtClientTimezone = dateTime.withZone(dtzConversion);` with `dateTime` millis is 1443650400000 (30.09.2015 22:00:00) and `dtzConversion` is 'Europe/Berlin', now `dtClientTimezone` millis are also 1443650400000. Why? The millis should be 2 hours greater. Isn't it? – opfau Oct 12 '15 at 13:03
  • Maybe the timezone of `datetime` was set to German timezone then no adjustment would be taken. Updated the code with an example. – flo Oct 12 '15 at 13:04
  • Do you mean such like al local time zone? In my case it happens on the server so I only want to convert these millis to a specific time zone. I am a little bit confused with joda time. – opfau Oct 12 '15 at 13:34
  • Yes, if you use DateTime.now(), a constructor without `DateTimeZone` paramter or parse a String without a timezone/offset, the DateTime object is created with the system's timezone. – flo Oct 12 '15 at 13:41
  • If you are reading datetime from a source not providing a timezone, you should consinder using the `LocalDate[Time]` classes. These are build to represent date/time values without timezones. When it comes to timezones, the user is explicitly forced to think about correct handling. It seems to me, that your method is build to meet exactly this requirement. – flo Oct 12 '15 at 13:47
  • The dateTime which shall be converted is always UTC. In the 1st step I want to convert it to another time zone (client time zone) with also the millis. But when I read the javadoc withZone() method should change the millis, but does not :( – opfau Oct 12 '15 at 14:30
  • 1
    Difficult to explain without a whiteboard ;-) I think you are missing the link between `Instant`, `LocalDateTime` and `DateTime`. Read https://stackoverflow.com/questions/32437550/java-8-whats-the-difference-between-instant-and-localdatetime. This holds true also for joda time (where DateTime is like ZonedDateTime). – flo Oct 12 '15 at 14:53