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
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.
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
Related
I have many users and they are located in different timezones. When a user changes some data (for instance edits) with her or his timezone, others must see it with their timezone. For this what can I do? Firstly , I need to save date with UTC timezone and when user wants to get it, It does request to api and gets returned date. After that user can convert this date with its timezone. Other users also do so. I think it works such
In short:
if you have to deal with daylight saving time (DST), you have to stick to java.time.ZonedDateTime
If you don't care about DST - use java.time.OffsetDateTime
In any case for all communications use ISO8601 standard
When using Magnolia CMS' DateFieldDefinition class: if my computer's current date is not matching the saved date's Daylight saving time, the saved date's time will be incorrect.
The relevant class: info.magnolia.ui.form.field.definition.DateFieldDefinition.
The relevant Vaadin component "Date and Time Input with DateField".
Another person seemed to have the same problem.
EDIT: Magnolia CMS appears to have a ticket about this issue already
Example:
In this example, I am running Magnolia CMS locally.
My computer's current date is Oct 17th, 2016
My computer's TimeZone is "Switzerland/Zurich"; hence I am on GMT+2 for the current date (summer time for my time zone)
In Magnolia Admin Panel, I save a date on Nov 3rd, 2016, hence that date is in winter time for my time zone, so GMT+1
That's where it gets interesting:
I change my computer's date to Nov 2nd, 2016, hence I am on GMT+1 (winter time for my time zone)
In Magnolia Admin Panel I open that date, it shows one-hour less.
Illustrations
The date/time implementation in Magnolia 5 was (and possibly still is) rather bad because of several issues:
It failed to distinguish between points in time (e.g. Skype appointment with someone possibly in another time zone) and "concept" times (e.g. a note when to make breakfast - it will always be at 7:00, no matter what time zone, so it's not about a specific point in time but about the concept of 7 o'clock)
It saved dates as timestamps although dates are neither timestamps nor time spans. This inaccuracy lead to the next problem:
Since dates were treated as timestamps by Magnolia 5 and timestamps were always handled as "points in time" by Magnolia 5, dates were also treated as points in time by Magnolia 5 although this is always wrong. Dates are always just "concepts" (in above sense), e.g. dates of birth. If I'm born on 1st January 1980, then that's my date of birth, and that is so in every time zone. My date of birth is not 31st December 1979 in another timezone, like it would with the "point in time" semantics mentioned earlier.
Dates and times were saved as instances of Calendar in JCR, that is a timestamp with a timezone. When transferring data from one Magnolia instance to another (Export, Import, Activation), the actual timestamps were copied as they were, they were not converted to the timezone of the target system. This meant that when the target system finally read the values, it may have seen wrong dates and/or times unless it explicitly converted the values.
Magnolia used to use the Browser's time zone for reading dates/times from the user by the Vaadin date/time fields but the server time zone for storing them in JCR. This meant there was always an implicit translation that may or may not have been wanted in the business logic. In many cases wrong values would end up in the repository (e.g. when entering dates of birth), so the later processing based on them had a certain probability of going wrong. In any case it had to be expected that the date/time saved in the repository was not the one the user had entered.
In a support ticket I wrote to Magnolia about these isuees they said they had fixed it in Magnolia CORE 5.4.11, which will be available since 5.5.1. I haven't tested these fixes yet, but unless you use this fixed version I wouldn't recommend to expect a simple solution for your problem, which comes on top of the problems I mentioned above. I did so just to document how little room there is to get the correct behavior for your use case with provided classes unless you needed exactly the use case they had implemented.
If unix timestamp is the same across the world how is am I able to get local time.
Or is it based on the different timezones the timestamp is different. i.e. I am in US the current seconds from UTC 1970 is 5,000 but if I am in Asia and check timestamp it will be 4,000 seconds ?
UTC is the same for every country in the world, whether you check in the US or in Asia the value will be the same.
Local time is calculated by using a time-zone offset (usually provided through the IANA time zone database). This is added to UTC time to determine the "Local Time" since 1970.
Both oldschool java.util.Date and modern java.time.SystemClock are using System#currentTimeMillis() to get system time, so let's assume you have same Unix time value on both machines.
Unix time to local time conversion could be a Bachelor's degree thesis: you have to consider leap years, leap seconds, daylight savings time, some changes to country's timezones made by government. You can read more about all that in OpenJDK's tzdata sources.
So, you need both system time and tzdata to be the same on your machines.
I think epoch converter can answer your question:
http://www.epochconverter.com/
You will see that Unix time is the same across the world, and it will print date accordingly to your localization
I have a date stored in a database as a UTC date ('2015-04-24 00:00:00'). When I get this date (using Hibernate) on a server running in the Eastern US Timezone, is shown as the correct date, '2015-04-24 00:00:00'. However, when I get this data on a server running on AWS in the us-west-1 region, which I assume is Pacific Time, the date shows as '2015-04-23 20:00:00'. Does anyone know why this would happen? I assume it has something to do with the date converting to local time, rather than UTC, but how can I prevent this from happening? Thanks!
Short answer: Just convert your Date to utc
Somewhat longer answer: As long as we don't consider relativistic effects a date (or more appropriately named a point in time) doesn't have a time zone. But if you display it as a String there are many variants of displaying it. One kind of variation is the choice of a timezone.
If you don't take special care to use a specific time zone, many programs will choose the timezone that the machine is 'living' in, which is configured on the os level and set to the time zone that is apropriate for the location the computer is most of the time.
My embedded Java application running on Linux should allow the user to change the timezone through a GUI. My application is running in an OSGI container (see below why I believe this is relevant) and should not need to restart before using the new timezone.
What is the recommended way of persistently setting the timezone from my Java/OSGi application?
I can think of the following approaches, for which I list some Pros and Cons. Am I missing something? What's recommended?:
From the app, change the underlying OS timezone, additionally use TimeZone.setDefault(...) for the currently running JVM and renew all Clock instances which hold the old TZ (so some kind of event is necessary). Con: this method is OS dependent and quite low level, also I would like to keep the OS clock UTC. Pros: OS takes care of storing the TZ, TZ is immediately correct upon next startup of app.
From the app, change the -Duser.timezone=... parameter used for launching. Con: very ugly, even lower level, but allows to leave the OS clock in UTC, while having the app start with the correct TZ. Also need to renew Clock instances on change.
Don't touch the OS, and only use TimeZone.setDefault(...) and call it early on startup. This will need a separate persistence (preferences) to save it. Here also, in the currently running JVM, all Clock instances which reference the old TZ, need to be renewed upon change (needs event). When running in an OSGi container, the startup order of bundles is not guaranteed, so I cannot be sure that the default TZ gets set before it is being used. How can I guarantee this? Also, JSR310 explicitely advises against using the "default TZ" in Clock.
Not use the "default" TimeZone at all, use a separate global variable and upon each conversion between Instant and LocalXXX values, pass the timezone explicitly. This gets rid of needing an event to update Clock instance. But we need to pay attention not to use LocalDate.now(clock), as this uses the clock's TZ (which is then no longer correct). How to have this global variable in OSGi? using ConfigAdmin? How to make code behave correctly which I have no control over (eg. logging time stamps)?
Edit: To get rid of the need to update the Clock, I could use a clock which always checks the default TimeZone, but this seems suboptimal from a performance POV:
public class DefaultZoneClock extends Clock {
private final Clock ref = Clock.systemUTC();
#Override
public ZoneId getZone() {
return ZoneId.systemDefault(); // probed on each request
}
#Override
public Clock withZone(ZoneId zone) {
return ref.withZone(zone);
}
#Override
public Instant instant() {
return ref.instant();
}
}
Is that a good idea?
Edit 2:
About my performance concerns above: they are obviously not justified. When you call LocalDate.now(), internally a new SytemClock is built which sets the current ZoneID by searching it in a Map - this is exactly the same as using my DefaultZoneClock above, the difference being that using my code I can inject any other Clock for testing. (all client code would use LocalDate.now(clock) )
Answers below suggest not to change the JVM TimeZone but to do the conversion whenever it is necessary based on a user-defined TimeZone, this means that I have to take care not to use the java.time methods which call the TimeZone from Clock, eg. if I need a LocaTime use
// OK, TimeZone is set explicitely from user data
LocalTime t = clock.instant().atZone(myUserZoneID).toLocalTime();
// Not OK, uses the Clock's internal TimeZone which may not have been set or updated
LocalTime t2 = LocalTime.now(clock);
In my experience, dates/times should always be represented internally using UTC. Only ever convert to a local time when showing it to a user. At that point you also have the requirement to format it according to the user's locale.
So the question becomes, how do you know the user's timezone and locale? It depends on the nature of the application. If it's a single-user desktop app then you should either look these up in the OS or use configuration stored with the Config Admin service. If it's a multi-user web application then you will probably have some user-related information in the web session; or use the Accept-Language header or even geo-location.
UPDATE
Poster clarified that the application is single-user on an embedded device. In this case isn't it easier just to query the current system timezone each time there is a requirement to display the time? This avoids nasty global variables, and it also allows your application to respond dynamically to changes in the timezone, for example if the user carries the device from one place to another.
I don't believe you should call TimeZone.setDefault from your Java application, because where are you going to get this information from? Direct user entry perhaps, but wouldn't the user prefer to set it in the OS, so that all applications can get it?
You seem to be making a mountain out of a molehill, working hard to make a simple problem into a complicated one.
Treat Date-Time Values Like Localizing Text
Localizing date-time is, well, a localization problem. Approach it in a manner similar to what you would do if some users speak French, some Italian, and some German.
Do all your internal work, such as lookups and key values, in one language, say English, even if none of your users speak English.
For date-time, the equivalent is keeping internal values in UTC time zone. Your business logic, file storage, and database records should all use UTC. If it is critical to know the original time zone and/or original input, store that as an additional piece of information in addition to the UTC-adjusted value.
When it comes time to display to the user, or export data for the user, you would use those English strings and keys to look up French or Italian or German translation. Which language? Three possibilities:
The user’s computing environment’s default language (JVM defaults, http headers, JavaScript query, whatever)
The user’s explicitly chosen language (our app asked the user)
The language appropriate to the data’s context.
For the first two, somewhere somehow you keep a profile for each user. In a web app, we use a session object. In a single-user "desktop" app, we use a Singleton. For a user’s chosen language, persist to a database or file storage so as to remember for future work sessions by this user.
Same goes for date-time. When presenting or exporting data, if the context does not dictate a time zone then detect their current time zone from their computing environment. If time zone is critical, or users are highly mobile and crossing time zones, then ask the user for their choice of time zone. Provide a list of proper time zone names. Remember this choice for future work sessions by this user.
Specify Time Zone On Date-Time Objects
Both the Joda-Time library and the java.time package in Java 8 make it easy to adjust a date-time object’s assigned time zone to and from UTC. You should be changing the time zone here, on the data value objects, rather than changing the JVM’s default or the OS locale settings.
Logging In UTC
As for logging and other system matters, that should be done in UTC. You can always later convert that UTC value to a local time zone later when investigating an issue. Or include the user’s localized date-time in your logging event’s message if relevant.
Do Not Mess With Clock
I would not mess with the java.time Clock when deployed in production. The main intention for this class is testing. You can plug in a bogus Clock to lie about the current date-time to create testing scenarios. You could plug in a Clock in production, but it makes much more sense to me to specify the desired time zone on your date-time objects.
Example
For example, say the user wants an alarm to fire at 7:30 AM. You either ask the user or otherwise determine their desired time zone is in Montréal. Here is unrealistic code in Joda-Time (java.time would be similar).
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
DateTime alarmMontréal = DateTime.now( zone ).plusDays( 1 ).withTime( 7 , 30 , 0 , 0 );
DateTime alarmUtc = alarmMontréal.withZone( DateTimeZone.UTC );
We display alarmMontréal to the user, but store alarmUtc in the database. Both represent the same moment in the timeline of the history of the Universe.
Say the user flies to Portland Oregon US in the meantime. If we want the alarm to fire at the same moment unchanged, no change needed. To display when that alarm will fire in Portland time, we create a new immutable object adjusting to yet another time zone.
DateTime alarmPortland = alarmUtc.withZone( DateTimeZone.forID( "America/Los_Angeles" ) ); // 3 hours behind Montréal, 04:30:00.000.
If we are going to call our Uncle in India at that time, we send him an appointment confirmation email using the result of this code:
DateTime alarmKolkata = alarmUtc.withZone( DateTimeZone.forID( "Asia/Kolkata" ) );
We have four DateTime objects, all representing the moment in the timeline of the Universe:
zone America/Montreal
alarmMontréal 2015-01-14T07:30:00.000-05:00
alarmUtc 2015-01-14T12:30:00.000Z
alarmPortland 2015-01-14T04:30:00.000-08:00
alarmKolkata 2015-01-14T18:00:00.000+05:30
LocalTime
If in a different scenario you had wanted 7:30 in whatever local time zone the user happened to be in, then you would use a LocalTime, which is merely the idea of seven-thirty in the morning in any time zone. A LocalTime is not tied to the timeline of the history of the Universe.
Both Joda-Time and java.time offer a LocalTime class. Search StackOverflow for many examples and discussions.
Here is an overly-simplistic example using LocalTime if the business rule is "Fire the alarm if the current time is after 07:30:00.000 in whatever locality the user/computer/device happens to find itself now":
Boolean alarmFired = Boolean.FALSE;
LocalTime alarm = new LocalTime( 7 , 30 );
// …
DateTimeZone zoneDefault = DateTimeZone.getDefault(); // Use the computer’s/device’s JVM’s current default time zone. May change at any moment.
if ( LocalTime.now( zoneDefault ).isAfter( alarm ) ) {
DateTime whenAlarmFired = DateTime.now( DateTimeZone.UTC );
alarmFired = Boolean.TRUE;
// fire the alarm.
}
Use UTC For History
Notice that if we are tracking a history of when the alarm fires, we should do so in UTC as a DateTime. We may also want to know at what local time that alarm fired. If we know or record the time zone, we can always re-create that. Or we may choose to also record the current local date-time. But that local value is secondary information. Primary tracking should be by UTC.
Explicitly Specify Time Zone
Note how we specify the time zone explicitly as the default. It would be shorter to use LocalTime.now() as that does indeed use the JVM’s current default time zone.
We are talking about the difference between this…
LocalTime now = LocalTime.now(); // Implicit reliance on JVM’s current default time zone.
…and this…
LocalTime now = LocalTime.now( DateTimeZone.getDefault() ); // Explicitly asking for JVM’s current default time zone.
Implicit reliance on the default time zone is a bad practice. For one thing such reliance encourages the programmer to be thinking in a local date-time frame of reference when she should instead develop a habit of thinking in UTC. Another problem is that implicitly relying on the default time zone makes your code ambiguous in the sense that the reader is not sure if you meant to use the default or just didn’t know better (which is all too often a cause of problems in date-time handling).