Search code examples
javaandroidtimezonesimpledateformat

Android device system time changes TimeZone of server date string when converting it to Date


I have to check if difference between time on server and Android device system time more then 1 hour. For now I have this string from server:

2020-08-24T11:50:18.613+0300

these is constant I use for SimpleDateFormat:

private static final String SYSTEM_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"

problem is when I try to convert string date to Date class I am getting this:

Mon Aug 24 13:50:18 GMT+05:00 2020

As I understand +05:00 there is because it is time zone which set at Android device as default. That is how I get this Date:

Locale locale =  new Locale("ru","RU");
DateFormat df = new SimpleDateFormat(SYSTEM_FORMAT, locale);
df.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
Date date = df.parse(serverDate);

As you can see even setting time zone to +3 (Moscow time) does not make Date which I expect. I know I can compare it using just string, but demands are to compare Dates


Solution

  • It looks like there is some gap in your understanding of Zone-Offset in the date-time string. The date-time string 2020-08-24T11:50:18.613+0300 means it is the date-time at the Zone-Offset of +0300 hours i.e. the corresponding date-time string on UTC will be 2020-08-24T8:50:18.613+0000.

    Note that java.util.Date lacks time-zone and zone-offset information. It just has the number of milliseconds since the epoch of 1 January 1970, 00:00:00 UTC. When you print a java.util.Date using an instance of SimpleDateFormat, you print the string representing the date-time in the time-zone set into the instance of SimpleDateFormat. You can understand it from the following example:

    import java.text.DateFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Locale;
    import java.util.TimeZone;
    
    public class Main {
        public static void main(String[] args) throws ParseException {
            // Parse the date-time string to java.util.Date
            String serverDate = "2020-08-24T11:50:18.613+0300";
            final String SYSTEM_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
            DateFormat dfSource = new SimpleDateFormat(SYSTEM_FORMAT);
            Date date = dfSource.parse(serverDate);
            System.out.println(date);
    
            // Get the date-time string for the time-zone of Europe/Moscow from
            // java.util.Date
            Locale locale = new Locale("ru", "RU");
            DateFormat dfTarget = new SimpleDateFormat(SYSTEM_FORMAT, locale);
            dfTarget.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
            System.out.println(dfTarget.format(date));
        }
    }
    

    I suggest you stop using the outdated and error-prone java.util date-time API and SimpleDateFormat. Switch to the modern java.time date-time API and the corresponding formatting API (java.time.format). Learn more about the modern date-time API from Trail: Date Time. If your android version is not compliant with Java-8, you can backport using ThreeTen-BackportCheck. Check How to use ThreeTenABP in Android Project.

    Using modern date-time API:

    import java.text.ParseException;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    import java.time.format.DateTimeFormatter;
    
    public class Main {
        public static void main(String[] args) throws ParseException {
            // Given date-time string
            String serverDate = "2020-08-24T11:50:18.613+0300";
    
            // Date-time formatter
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    
            ZonedDateTime zdtServer = ZonedDateTime.parse(serverDate, formatter);
            System.out.println("Given date-time: " + zdtServer);
            System.out.println("Zone Offset of the given date-time: " + zdtServer.getOffset());
    
            // Convert it to some other time-zone e.g Etc/UTC
            ZonedDateTime zdtatUTC = zdtServer.withZoneSameInstant(ZoneId.of("Etc/UTC"));
            System.out.println("Equivalent date-time at UTC: " + zdtatUTC);
    
            // Convert it to some other time-zone e.g Europe/London
            ZonedDateTime zdtInLondon = zdtServer.withZoneSameInstant(ZoneId.of("Europe/London"));
            System.out.println("Equivalent date-time in London: " + zdtInLondon);
        }
    }
    

    Output:

    Given date-time: 2020-08-24T11:50:18.613+03:00
    Zone Offset of the given date-time: +03:00
    Equivalent date-time at UTC: 2020-08-24T08:50:18.613Z[Etc/UTC]
    Equivalent date-time in London: 2020-08-24T09:50:18.613+01:00[Europe/London]
    

    Note that the modern date-time API has a class called, ZonedDateTime which has time-zone information along with the date & time information.