Reputation: 924
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
Upvotes: 1
Views: 1879
Reputation: 86276
There’s no need to worry about offset from UTC or time zone when comparing times. Comparison across offsets goes smoothly.
I am using java.time, the modern Java date and time API. Let’s first define a couple of useful constants:
private static final Duration TOLERANCE = Duration.ofHours(1);
private static final DateTimeFormatter serverFormatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendPattern("XX")
.toFormatter();
Now we can do:
String serverDateTimeString = "2020-08-24T11:50:18.613+0300";
OffsetDateTime serverTime = OffsetDateTime.parse(serverDateTimeString, serverFormatter);
System.out.println("Server time: " + serverTime);
ZoneId deviceTimeZone = ZoneId.of("Asia/Yekaterinburg");
OffsetDateTime deviceTime = OffsetDateTime.now(deviceTimeZone);
System.out.println("Device time: " + deviceTime);
if (deviceTime.isBefore(serverTime.minus(TOLERANCE)) || deviceTime.isAfter(serverTime.plus(TOLERANCE))) {
System.out.println("Difference between time on server and Android device system time more than 1 hour");
} else {
System.out.println("Difference between time on server and Android device system time 1 hour or less");
}
I have used your string from the question, so we shouldn’t be surprised that the snippet tells us there’s a great difference between the two times when I run it now:
Server time: 2020-08-24T11:50:18.613+03:00 Device time: 2020-08-24T23:08:57.939565+05:00 Difference between time on server and Android device system time more than 1 hour
For the sake of the experiment let’s also try setting the device time to the time from your question:
OffsetDateTime deviceTime = OffsetDateTime.of(2020, 8, 24, 13, 50, 18, 0, ZoneOffset.ofHours(5));
Server time: 2020-08-24T11:50:18.613+03:00 Device time: 2020-08-24T13:50:18+05:00 Difference between time on server and Android device system time 1 hour or less
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
org.threeten.bp
with subpackages.java.time
was first described.java.time
to Java 6 and 7 (ThreeTen for JSR-310).Upvotes: 2
Reputation: 79085
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.
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.
Upvotes: 2
Reputation: 18568
You don't really have a time zone but rather an offset.
To correctly convert the String
you get from a servery, you should use java.time
instead of the outdated java.util.Date
or java.util.Calendar
.
Here's an example that uses a suitable class for your situation (java.time.OffsetDateTime
):
public static void main(String[] args) {
String stringFromServer = "2020-08-24T11:50:18.613+0300";
OffsetDateTime timeFromServer = OffsetDateTime.parse(
stringFromServer,
DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSZ")
);
System.out.println(timeFromServer.format(
DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss XXX uuuu", Locale.ENGLISH))
);
}
The output of this (the OffsetDateTime
formatted using a pattern that mimics the one you posted) is
Mon Aug 24 11:50:18 +03:00 2020
You can use a ZonedDateTime
as well, but then you will have to add a ZoneId
, ZoneId.of("Europe/Moscow")
, most likely...
It can be done like this using the already created OffsetDateTime timeFromServer
:
ZonedDateTime moscowTime = timeFromServer.atZoneSameInstant(ZoneId.of("Europe/Moscow"));
ZonedDateTime berlinTime = timeFromServer.atZoneSameInstant(ZoneId.of("Europe/Berlin"));
and System.out
ing them without a special format would give you these lines:
2020-08-24T11:50:18.613+03:00[Europe/Moscow]
2020-08-24T10:50:18.613+02:00[Europe/Berlin]
Please note: Since there's API Desugaring for Android you can use Java 8(+) functionality in API levels below Android 26.
Upvotes: 2