Alexandr
Alexandr

Reputation: 1901

Problems with incorrect timezone on Android

Now correct time zone for Moscow is UTC +3. But Android 4.4.4 only knows UTC +4 for Moscow.

And java.util.Date give wrong time:

Date now = new Date();    
Sat Nov 21 00:37:24 GMT+04:00 2015
1448051844024 in (milliseconds)

Using Joda org.joda.time

DateTime nowWithCorrect = new DateTime()
                              .withZone(DateTimeZone.forID("Europe/Moscow"));
2015-11-20T23:37:24.023+03:00
1448051844024 in (milliseconds)

But problem is the user (on devices with incorrect time zone) has manually corrected time on device. And joda and java give incorrect time in milliseconds.

I get from web service timestamp and on device calculate different with local time. But local time incorrect and give incorrect results.

I want check joda and java time and manually to correct timestamp.

Question: can I get different between time zone and different between time in hours (now and nowWithCorrect)? For example: differentTimeZone = 1, differentTimeHours = 1

Upvotes: 4

Views: 4449

Answers (2)

Oleksandr Albul
Oleksandr Albul

Reputation: 1741

You could find the difference between joda-time timezone (which is based on last IANA) and android system timezone:

long diff = DateTimeZone.getDefault().getOffset(yourTimeStapm) - TimeZone.getDefault().getOffset(yourTimeStapm);

Also you could use fork of joda-time which is used system timezones: https://gitlab.com/olekdia/common/utils/support-joda-time

Upvotes: 0

Basil Bourque
Basil Bourque

Reputation: 340350

Confusing Time Zone Changes In Russia

Russia has gone through some confusing time zone changes in recent years, with Moscow’s offset-from-UTC shifting back-and-forth between +03:00 and +04:00. See Wikipedia pages on Time in Russia and Moscow Time.

Before autumn of 2011, Moscow had standard time was +03:00 with a Daylight Saving Time (DST) of +04:00.

Starting in the autumn of 2011, Russia took a decision to stay permanently on DST, +04:00, and abolish the standard time of +03:00. See this RT.com article.

In July 2014, that decision was drastically altered. Now Russia is permanently on a standard time of +03:00 and has abolished DST (no more +04:00).

Outdated tz Database

So I assume your troubles are due to your time zone tz database (formerly known as the Olson database) being outdated. The real Java platform has a tz database, and its host operating system likely has a tz database. Joda-Time has its own tz database. I assume Android does as well, though I do not know about Android.

Obviously keeping all these tz database up-to-date is a real chore.

For Joda-Time, simply replace your Joda-Time library with the latest. While you can replace just the tz database in Joda-Time, as far as I can remember, there are virtually no backward-compatibility issues with Joda-Time 2, so no reason not to update the entire library. But read the release notes to be sure. If using Joda-Time, this is the only minimum requirement for updating; I would recommend updating Android, Java, and host OS as well but not necessary.

For the real Java platform, recent versions made it much easier to update the tz database. Previous versions required some hacking. Alternatively, update to the latest Java 8 to get the latest library.

For your host OS, its regular updating system probably contains tz updates. However, some of those updates may lag behind. So you may need to do a manual update.

Work In UTC

The best practice for date-time work is usually to do all of your back-end work in UTC. Business logic, data storage, database, data exchange, and such should all be in UTC. Adjust into a time zone such as Europe/Moscow only when expected/desired by the user or data sink.

In Java 8 and later, we would use the built-in java.time framework. Use Instant for a moment in UTC. Specify a ZoneId to get a ZonedDateTime when a time zone is needed. But Java 8 technology is not yet available in Android. I believe there is back-port library for java.time for Android, but I do not know the details.

For Joda-Time, ask for the current moment in UTC.

DateTime nowUtc = DateTime.now( DateTimeZone.UTC );

If you cannot trust the user’s local device/computer clock to be accurate and set correctly, then this UTC date-time will be wrong. Nothing you can do about that. Instead trust an outside source, but that assumes a network connection.

Adjust into Moscow time as needed.

DateTime nowMoscow = nowUtc.withZone( DateTimeZone.forID( "Europe/Moscow" ) );

If the user’s tz database for Joda-Time is outdated, this will return a wrong result. No way to prevent that as you cannot predict what the Russian authorities will do next to their time-keeping rules. The only solution is to keep your app updated with a Joda-Time library that has an updated tz database. Or, again, trust an outside source such as your server or some other web service, but that assumes a network connection.

Verify Count-From-Epoch

If you are getting confused and want to verify a date-time object’s true value, look at the count-from-epoch.

Both Joda-Time and the old java.util.Date/.Calendar classes count milliseconds from first moment of 1970 UTC. These values are shown in the Question. See how both milliseconds-from-epoch values in the Question are the same, so same moment on the timeline but an incorrect adjustment into Moscow time by Android's Date class (almost certainly because of an outdated tz database).

Note that java.time uses a different count-from-epoch, counting nanoseconds from same epoch (1970 UTC). In Joda-Time, call getMillis to get the count-from-epoch. In java.util.Date, call getTime.

Upvotes: 2

Related Questions