I am testing my app in different timezones. I manually changed my physical phone's timezone to be London UK which is GMT+00:00
However, when I print the timezone using myCalendar.getTimeZone().getDisplayName(true, TimeZone.SHORT), it prints:
GMT+01:00
Why's it adding an hour to the offset?
EDIT:
By setting the getDisplayName's first parameter to false, I get the correct GMT+00:00 but I am not sure why I should be setting it to false. As far as I know, London UK is always GMT+00:00? Am I wrong?
As far as I know, London UK is always GMT+00:00? Am I wrong?
Yes, you are wrong. The United Kingdom observes Greenwich Mean Time (GMT) in the winter, and observes daylight saving time, locally called "British Summer Time" (BST), in the summer.
GMT = UTC+00:00
BST = UTC+01:00
Reference here, and here.
According to the API, getDisplayName()'s first parameter indicates if daylight savings should be used.
Returns a name in the specified style of this TimeZone suitable for
presentation to the user in the default locale. If the specified
daylight is true, a Daylight Saving Time name is returned (even if
this TimeZone doesn't observe Daylight Saving Time). Otherwise, a
Standard Time name is returned.
This is probably why the time is an hour ahead with that value set to true, as a value of true will cause a daylight savings hour even if it isn't observed in that timezone.
Related
I have a web application that returns a booking time based on the country where the event was performed.
Eg: If the booking was created in India at 02-JUNE-2020 1700 IST,then time returned is:
2020-06-02T17:00:00+0530
If the booking was created in Thailand at 02-JUNE-2020 1700 Thai Time,then time returned is:
2020-06-02T17:00:00+0700
Now I have to store all this in a system in UK time,so the data would be:
for India,in UK system: 2020-06-02T12:30:00+0100
for Thailand,in UK system: 2020-06-02T11:00:00+0100
I know I can use the zone indicator of +0530 to convert to milliseconds offset by using
TimeZone.getAvailableIDs(milliseconds);
and find the corresponding timezone to do a reverse integration.
But is there an easy way to translate the IST to UK time directly in java ?
+0530 is not actually indicative of any particular time zone. A time zone could be, say, Europe/Amsterdam. This is +0100 in winter and +0200 in summer, and the zone Europe/Paris has the exact same offset at the exact same dates. Whilst unlikely, it is entirely possible that 5 years from now this is no longer the case. Note that +0100 does not accurately describe Europe/Amsterdam (it'd be wrong in summer), and cannot disambiguate between amsterdam and paris, which is why it's not good enough, generally. If this is just what you've been given and you can't change it, yea, getAvailableIDs is one way to at least attempt to convert +0530 into a zone, but note that usually you get many answers, so I don't know how you'd figure out how to pick the 'right' zone. Consider changing the system so that you get this timezone, the full ID, as part of the input instead.
Let's say you have obtained the zone, somehow.
Given 2020-06-02T17:00:00+0530 - you can translate this to the exact moment in time that the event being described by this timestamp has/will occur. That's presumably important; if you want an alarm to go off at that time anywhere on the planet you can now make that happen. That you store this 'in UK time' is just an implementation detail, that doesn't matter: You're storing the instant in time this event occurs, and not the way the human-oriented system that created this timestamp would refer to it (which is, presumably: '5 in the evening, on the second of june in 2020, in india').
But, you indicate a need to convert back from this 'exact instant in time' back to the zoned time.
Why?
If the answer is: So that it is familiar to the human, because the human I will end up printing this string to is definitely in india, you potentially have some issues if you go with the not-human-relevant zone ID of '+0530'; you optimally want to go with the more human-relevant zone ID of 'Asia/Kolkata', for example.
Okay, and now in java please!
an instant in time is best represented with an instance of java.time.Instant. This has no timezone info; it just marks a moment in time. (internally it stores as UTC, but that is an implementation detail. these things are timezoneless).
Once you have an Instant, and you have a TimeZone, you can do:
Instant x = ....; // obtain an instance somehow.
ZoneId zone = ZoneId.of("Asia/Kolkata"); // get a zone somehow.
ZonedDateTime zdt = x.atZone(zone);
You can print a zdt, for example with a java.time.format.DateTimeFormatter instance, and it'll render it as somebody in india would prefer.
If you have instead stored, say, a string containing the text 2020-06-02T12:30:00+0100, you can go from there to an instant rather easily, and then you can .atZone your way back to indian time.
In Joda-Time version 2.9.9 I want to remove time part of DateTime variable.
Only for time zone Asia/Tehran and some dates like (2036-03-21, 2037-03-21, ...) it returns 1:00:00 in time part of result.
I also checked the Joda-Time source code but I couldn't find any problem.
The code is:
DateTime dt = new DateTime(2036, 03, 21, 10, 0, DateTimeZone.forID(Asia/Tehran));
dt = dt.withTimeAtStartOfday();
Actual result:
2036-03-21T01:00:00.000+04:30
Expected result:
2036-03-21T00:00:00.000+04:30
Time is not zero. This only happens for zone Asia/Tehran.
My system config:
Java version: 1.7.0_72 - I have to use Java 7
Joda-Time: 2.9.9
I solved this problem by converting DateTime to LocalDate, but I want to know why this problem happens?
This is because Iran switches from Standard time to Daylight Savings time at 00:00 on the 21st or 22nd of March (whichever day contains the astronomical equinox).
In 2036 this happens on the 21st. In 2018 it happens to fall on the 22nd.
In short, the time jumps from 2036/03/20 24:00 to 2036/03/21 01:00. The hour from midnight to 1 AM does not exist on that specific day.
When writing code that deals with time, ALWAYS keep in mind that unexpected small offsets from expected results are almost surely due to administrative time changes. This is even more true for historical dates, where offsets could be any number of minutes and seconds, not just whole or half-hours.
Strange thing. I have SQLite Android database with dates kept as long values. I read them as Date objects ex.:
new Date (cursor.getLong(4))
Next when displaying I convert Date objects to String with toString() method. However sometimes the displayed String contains CET and sometimes CEST.
Sure the fact that time zone info is added is not surprising. What is surprising the fact that at the same device, with values get from database in the same time, being long values thus not containing any zone time information, java sometimes add CET and sometimes CEST. Why there is such a difference?
The only difference is that long value which gives in result CEST has time equal to 00:00:00 while those giving in result CET has time different.
Any idea?
The values themselves are totally time-zone agnostic, but your device is not. Your device has two time zones, CET and CEST, as part of its locale. Dates that fall during the time when daylight savings time was/is/will be active are given in CEST, other dates are reported as CET.
If you set your device to a locale that doesn't observe daylight savings time, only that one time zone will be reported.
To see why this makes sense, consider if you asked me what time it is now, and I said "13:35 CEST." Inasmuch as CEST is UTC+2, I'm correct, but you'd likely be confused. Because CEST isn't used at this time of year, it only makes sense to gives times in CET. That's why the timezone varies depending on the date.
When I run the below line,
System.out.println(java.util.TimeZone.getDefault());
I got the following output.
sun.util.calendar.ZoneInfo[id="Asia/Calcutta",
offset=19800000,
dstSavings=0,
useDaylight=false,
transitions=6,
lastRule=null]
and
System.out.println(Locale.getDefault()); gives
`en_US`
My doubt is
How could the Locale be en_US, When My Zone id is Asia/Calcutta?
in the first output, I haven't understood what are offset, dstSavings, useDaylight, transitions and rules ?
Could anybody help in understanding these.
Thanks in advance...
Locale has nothing to do with TimeZone, you can setup your computer in French in Australia if you want... you won't need France TimeZone for that.
To know more about TimeZone, you should read theses :
TimeZone
What is a TimeZone
The class that actualy give you the toString() : ZoneInfo
useDaylightTime
public abstract boolean useDaylightTime()
Queries if this time zone uses daylight savings time.
What is Daylight Saving Time.
getDSTSavings
public int getDSTSavings()
Returns the amount of time to be added to local standard time to get local wall clock time.
So this is the difference between the UTC + TimeZone + (DSTSavings - 0 or 1 hour). If you are currently in DST savings mode, will return 1 hour.
rules
Rules mean the date when the DST is active and date when it is no more. More info SimpleTimeZone.
transitions
This array describes transitions of GMT offsets of this time zone, including both raw offset changes and daylight saving time changes. A long integer consists of four bit fields.
The most significant 52-bit field represents transition time in
milliseconds from Gregorian January 1 1970, 00:00:00 GMT.
The next 4-bit field is reserved and must be 0.
The next 4-bit field is an index value to offsets[] for the amount of daylight saving at the transition. If this value is zero, it means
that no daylight saving, not the index value zero.
The least significant 4-bit field is an index value to offsets[] for total GMT offset at the transition.
If this time zone doesn't observe daylight saving time and has never
changed any GMT offsets in the past, this value is null.
Check this question to understand how Locale.getDefault() actually works.
As for your output for System.out.println(java.util.TimeZone.getDefault());
DST Savings: The base implementation returns 3600000 (1 hour) for
time zones that use daylight savings time and 0 for timezones that
do not
Offset: This is the offset of your timezone w.r.t GMT. For India,
it is 5hr30min which is 19800000 ms
UseDaylight: This shows that there is no daylight adjustment for
this timezone .
Transitions: This refers to the daylight saving time transitions
of a timezone.
LastRule: Returns a SimpleTimeZone object representing the last GMT
offset and DST schedule or null if this time zone doesn't observe
DST.
Hope this helps.
I am trying to get current time in specific time zones. I tried following code.
Calendar j = new GregorianCalendar(TimeZone.getTimeZone("US/Mountain"));
j.setTimeInMillis(Calendar.getInstance().getTimeInMillis());
System.out.println(j.get(Calendar.HOUR_OF_DAY)+":"+j.get(Calendar.MINUTE));
TimeZone tz = TimeZone.getTimeZone("US/Mountain");
System.out.println("tz.getRawOffset()"+tz.getRawOffset()/3600);
System.out.println(tz.getDSTSavings());
System.out.println
(tz.inDaylightTime(new Date()));
The answer I got is surprising -
16:57 - wrong by 1 hr
tz.getRawOffset()-7000
3600000
true - why daylight saving is true for Arizona?
How to get the correct wall clock time of Phoenix or any other city in US?
Arizona is in the Mountain timezone, but doesn't observe DST. If you specify the timezone "US/Mountain", then the computer will apply the rules used by most states in the Mountain time zone, which include observing daylight savings time. To get the rules for Arizona (which don't include DST), you want the timezone "US/Arizona" (or "America/Phoenix"). In the Navajo nation, you want the timezone named "Navajo".
To save yourself some of the trouble, always try to use the names from "America/*" where you can pick the name of a city that has the same timezone rules as the place you're interested in.
To get the correct time in the correct timezone for any given city in the world, you simply have to familiarize yourself with the names in the Olson timezone database and their meanings. While you usually think of the term "time zone" to mean the time of day in the middle of the winter (when everybody observes standard time), in the Olson database a timezone name represents the entire history of daylight savings time rules and timezone rules for a particular region.
As an example, even though Indiana now observes Eastern time and observes DST (except for a few counties right near Chicago which are on Central time like Chicago), before 2006 they didn't observe DST. A timezone named "US/Indiana" (or "America/Indianapolis") was created to cover this region, an even today, you would still want to use the timezone "America/Indianapolis" when talking about Indiana, so that queries about dates and times before 2006 could be answered correctly.
Most of Arizona does not observe Daylight Savings Time, but the Navajo Nation inside Arizona does observe DST.
I am providing the modern answer. Don’t use the classes Calendar, GregorianCalendar, TimeZone and Date. They are all poorly designed and fortunately all long outdated.
java.time
It’s simple when you know how:
ZonedDateTime arizonaExceptNavajo = ZonedDateTime.now(ZoneId.of("America/Phoenix"));
System.out.println(arizonaExceptNavajo);
When I ran this code just now, the output was:
2019-10-23T04:07:23.034-07:00[America/Phoenix]
The US/Mountain time zone ID is deprecated. It’s a link to America/Denver, and America/Denver does use summer time (daylight saving time, DST). Modern time zone IDs have the form region/city where region is either a continent like America or an ocean like Pacific.
As others have said, summer time is used on one place in Arizona, the Navajo Nation. The Navajo time zone ID mentioned is deprecated too. Use America/Denver:
ZonedDateTime navajoNation = ZonedDateTime.now(ZoneId.of("America/Denver"));
System.out.println(navajoNation);
2019-10-23T05:07:23.037-06:00[America/Denver]
Since summer time is still in effect, the time of day is one hour ahead compared to the one for Phoenix above.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Navajo Nation on Wikipedia.
The zone information can be obtained directly for many major cities worldwide. This includes Phoenix, which has the zone identifier "America/Phoenix".
You can find the list of available zone identifiers using the method TimeZone.getAvailableIDs() or by manually inspecting the contents of the JRE lib/zi directory.
As other posters have noted, the "US/Arizona" zone information is distinct from "US/Mountain".