androidjodatimeandroid-jodatime

Why is JodaTime timezone shifting a date time?


When the string "2017-04-21T17:46:00Z" is passed into the first method the resulting formatted date string is "06:46 21 Apr 2017". Why is the hour moving by eleven hours? The input strings are being provided by an HTTP server application in JSON. I thought the Z suffix referred to Zulu, ie GMT.

private static final String DATE_TIME_FORMAT = "hh:mm dd MMM yyyy";

public static String formatTimestamp(String dateTimestamp) {
    DateTime dateTime = getDateTimeFromTimestamp(dateTimestamp);
    DateTimeFormatter fmt = DateTimeFormat.forPattern(DATE_TIME_FORMAT);
    return fmt.print(dateTime);
}

private static DateTime getDateTimeFromTimestamp(String dateTimestamp) {
    return new DateTime(dateTimestamp);
}

I suspect it relates to timezones but it's not clear how or where. The code is running on an Android device in the UK, in the GMT timezone.


Solution

  • I've made a test with java 7 and joda-time 2.7 (but not the Android's version)

    That's how I could reproduce the problem:

    // changing my default timezone (because I'm not in UK)
    DateTimeZone.setDefault(DateTimeZone.forID("Europe/London"));
    // calling your method
    System.out.println(formatTimestamp("2017-04-21T17:46:00Z"));
    

    The output is

    06:46 21 Abr 2017

    To check what's wrong, I've changed the date format to:

    DATE_TIME_FORMAT2 = "hh:mm a dd MMM yyyy Z z zzzz";
    

    Where a means "AM or PM", Z is the timezone offset/id, z is the timezone "short" name and zzzz is the timezone "long" name. Using this format, the output is:

    06:46 PM 21 Abr 2017 +0100 BST British Summer Time

    So the datetime created is 6PM, just one hour ahead of input, not eleven hours as you thought (actually if you change the format to HH instead of hh, the hours will be 18 instead of 06).

    Also note the timezone fields: +0100 BST British Summer Time. The first part (+0100) means that this DateTime is one hour ahead of GMT, and BST British Summer Time means it's in British's Daylight Saving Time.


    So, to have your output equals to your input, you have 2 alternatives:

    1. Change your default timezone to UTC:

    DateTimeZone.setDefault(DateTimeZone.UTC);
    System.out.println(formatTimestamp("2017-04-21T17:46:00Z"));
    

    The output will be:

    05:46 21 Apr 2017

    If you want to change the hours to be 17:46, change your date format, replacing hh by HH

    2. Use the DateTime constructor that receives a DateTimeZone:

    private static DateTime getDateTimeFromTimestamp(String dateTimestamp) {
        // creates a DateTime in UTC
        return new DateTime(dateTimestamp, DateTimeZone.UTC);
    }
    

    The output will be the same as alternative 1, but in this case you don't need to change the default timezone.

    For me, alternative 2 makes more sense, because: