No, I'm not talking about zone offsets --- those can vary during the year for a region based on e.g. DST. I'm talking about the actual time zones maintained by IANA. I understand these are not supported by ISO 8601, correct?
What are platforms doing to support identifying time zones in ISO 8601-like string representations? I notice that the latest Java date/time library is using an extended ISO 8601 format for this, e.g. 2011-12-03T10:15:30+01:00[Europe/Paris]. (See DateTimeFormatter API.)
Is there some converging convention (e.g. with other languages and platforms) for extending ISO 8601 to support time zone designation?
Update:
There's now a draft IETF proposal to extend RFC3339 with the time zone identifier in square brackets, among other things: https://datatracker.ietf.org/doc/draft-ietf-sedate-datetime-extended/
Original Answer:
I understand these are not supported by ISO 8601, correct?
Correct. ISO-8601 does not concern itself with time zone identifiers. IANA/Olson TZ names are not a "standard". They are just the most reliable thing we have. (Some may consider them the de facto standard.)
What are platforms doing to support this?
Support what exactly? This part of your question is unclear. If you mean to support IANA time zones, well that's all over the place. Some platforms have them built-in, and some rely on libraries. If you mean to support a string representation of an ISO-8601 date-time-offset + time zone ID, some platforms have this and some do not. You'll have to be more specific if you want to know more.
I notice that the latest Java date/time library is using an extended ISO 8601 format for this, e.g. 2011-12-03T10:15:30+01:00[Europe/Paris]. (See DateTimeFormatter API.)
I think you are talking about DateTimeFormatter.ISO_ZONED_DATE_TIME. The docs say specifically:
The ISO-like date-time formatter...
...extends the ISO-8601 extended offset date-time format to add the time-zone. The section in square brackets is not part of the ISO-8601 standard.
So this is Java's specific format, not a standard.
Is there some converging convention (e.g. with other languages and platforms) for extending ISO 8601 to support time zone designation?
As far as I know, there is currently no standard that covers the combining of an ISO8601 timestamp and an IANA time zone identifier into a single format. One could represent it many different ways, including:
2011-12-03T10:15:30+01:00[Europe/Paris] (this is the default in Java 8)
2011-12-03T10:15:30+01:00(Europe/Paris)
2011-12-03T10:15:30+01:00 Europe/Paris
2011-12-03T10:15:30+01:00 - Europe/Paris
2011-12-03T10:15:30+01:00/Europe/Paris
2011-12-03T10:15:30+01:00|Europe/Paris
2011-12-03T10:15:30 Europe/Paris (+01) (this is the default in Noda Time)
If what you're looking for is a way to include a ZonedDateTime or similar data in an API in a standardized manner, my personal recommendation would be to pass the time zone name in a separate field. That way, each portion of data is as good as it can be. For example in JSON:
{
"timestamp": "2011-12-03T10:15:30+01:00",
"timezone": "Europe/Paris"
}
The Answer by Matt Johnson is spot-on correct. I'll just add a few thoughts.
Time zone versus offset-from-UTC
An offset-from-UTC is merely a number of hours, minutes, and seconds ahead/behind UTC. Alone, this does make a date-time into a specific moment on the timeline. But it is not nearly as informative as including the official time zone name as well.
While there is no standard yet for including the time zone name, I do hope others follow the lead of the java.time classes in appending in square brackets the name of the time zone. This format seems sensible to me as it would be simple to truncate the square-bracket portion to be backward-compatible with non-savvy software.
For example:2011-12-03T10:15:30+01:00[Europe/Paris]. If the data were only 2011-12-03T10:15:30+01:00, we would be able to identify the moment on the timeline, but would not be able to adjust other moments into the same frame of mind as we would not know what rules of adjustment to apply. Zones such as Europe/Zagreb, Africa/Brazzaville, Arctic/Longyearbyen, and Europe/Isle_of_Man all share the offset of +01:00, but they may well have other adjustments in force differing from those of Europe/Paris. So if you were to try to add three days to the value 2011-12-03T10:15:30+01:00, you really cannot faithfully compute the result because you do not know what adjustments may need to apply such as DST cutovers that may be occurring during those three days.
A time zone defines the set of rules for handling anomalies such as Daylight Saving Time (DST). Politicians around the world enjoy making adjustments to their time zones, or even re-defining them. So these rules change frequently. Think of a time zone as a collection of offsets over time, many periods of time in history wherein each period had a particular offset in use in that particular region.
You can think of a time zone as a collection of offset-from-UTC values. In America/Los_Angeles part of this year is 8 hours behind UTC, and part of the year will be 7 hours behind UTC. That makes 2 points of data collected as part of that time zone.
Another example, in previous years, Turkey spent part of each year 2 hours ahead of UTC and part of each year 3 hours ahead. In 2016, that changed to indefinitely staying 3 hours ahead. So, multiple points of data in the time zone Europe/Istanbul.
Just use UTC
Personally I do not see much value in even using values such as 2011-12-03T10:15:30+01:00. Without a time zone, you might just as well use UTC alone. In this case, 2011-12-03T09:15:30Z (9 AM instead of 10 AM).
Generally the best practice is to use UTC when storing and exchanging date-time values. Think of UTC as the One-True-Time, with zoned or offset values being mere variations.
Related
A client's API that I am integrating with returns a time with the time zone as a short id (3 letter id). e.g.
9:00 MST
13:30 EDT
17:00 MDT
I realize this is bad practice (especially with the daylight savings), and short ids should be avoided, but unfortunately I have no way to get the client to change their api. Is there a clean way to convert these short ids to a property ZoneId? ZoneId.SHORT_IDS looks like the closest, but it doesn't include daylights savings. Worst case, I think I can just make my own map of short ids to ZoneIds since it's limited to the US
Time with zone makes no sense
13:30 EDT
A time-of-day plus a time zone makes no sense. Without the context of a date, there is no real meaning here.
The SQL-92 standard declares a TIME WITH TIME ZONE type, but neglects to define its meaning. I am not alone in being mystified by the SQL committee’s intention. And also, importantly, that data type is a misnomer: the SQL standard means offset when they say “time zone”.
Java offers an OffsetTime class. I presume this class exists merely for mapping through JDBC to that screwy SQL type of TIME WITH TIME ZONE. The Javadoc offers no real explanation as to the meaning of this class.
So what is your goal? I suggest you edit your Question to indicate what kind of processing you intend to do with such inputs. Perhaps we can guide you from there.
Pseudo time zones are not unique
You asked:
Is there a clean way to convert these short ids to a property ZoneId?
No.
These 2-4 character pseudo time zones are not defined, are not standardized, and are not unique.
CST — Do you mean Central Standard Time in the Americas? Or do you mean China Standard Time? Or Cuba Standard Time?
IST — Do you mean India Standard Time? Or Ireland Standard Time?
PST — Pacific Standard Time or Pitcairn Standard Time?
BST — Bangladesh Standard Time, Bougainville Standard Time, or British Summer Time?
AMST — Amazon Summer Time or Armenia Summer Time?
So, no you cannot cleanly determine a time zone from a pseudo zone. You can only guess. If you know for certain the domain of possible values you expect to receive, and you are certain as to their intended actual time zone, then you can create your own mapping.
But even then, there is no class in Java nor data type in SQL to represent a date with time zone. You would have to convert that time zone to an offset from UTC. And for that conversion, you would need a date to determine a moment to determine the offset in use at that moment by the people of that zone… which leads us back in a circle to point at the top of this Answer: A time with only a zone (or offset), but without the context of a date, makes no sense.
Reject senseless data
You said:
but unfortunately I have no way to get the client to change their api
Providing a time-of-day with an ambiguous pseudo time zone is like providing a money amount tagged with "dollar" while asking to convert to "francs".
We don't know if "dollar" means Canada Dollar (CAD), United States Dollar (USD), or a Australian dollar (AUD), or any of the twenty currencies with that name.
We don't know if franc means the franc CFA in West Africa, the Swiss franc, or some other currency with that name.
We don't have a date on which to look up a conversion rate.
So what would you do with such a request? What can you do? You would have to either ask for much more explicit definitions, or you would have to refuse the request.
I have seen code where they mention UTC, i just wonder what is the syntax for US pacific time.
Calendar cal_Two = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
is it like below.
Calendar cal_Two = Calendar.getInstance(TimeZone.getTimeZone("USP"));
Prefer ZonedDateTime and ZoneId over Calendar and TimeZone
Allow me the opportunity to recommend java.time, the modern Java date and time API. I am aware that your code lines are taken out of a larger context that I don’t know, so switching to java.time may be entail a bit more work than that. It will most probably be worth it.
If you are writing new code, use java.time throughout and forget about Calendar and the other old classes.
If you are writing code that needs to interoperate with legacy code using Calendar, still consider using java.time in your own code. Straightforward conversions exist for when you need to pass a Calendar to a legacy method.
Calendar and TimeZone are poorly designed and long outdated. The modern API is so much nicer to work with and generally lends itself to more concise and more natural code that it will be much easier to maintain.
Likely America/Los_Angeles will fulfil your purpose
I believe that the America/Los_Angeles time zone covers the part of the USA that uses Pacific Time (Pacific Standard Time in the winter and Pacific Daylight Time in the summer): California, Nevada, Washington and greater parts of Oregon and Idaho.
Always give time zones in the region/city format like America/Los_Angeles or Europe/Kiev. Other formats have been used previously and are still seen, but they are no longer encouraged. Particularly a lot of two, three, four and five letter abbreviations should be avoided since they are often not true time zones and often ambiguous. Even for UTC the recommended official ID is Etc/UTC (even though Etc hardly counts as a region of the Earth).
ZoneId zone = ZoneId.of("America/Los_Angeles");
ZonedDateTime zdt = ZonedDateTime.now(zone);
System.out.println(zdt);
Output when I ran this code just now:
2020-04-23T09:35:22.842667-07:00[America/Los_Angeles]
ZonedDateTime is the most natural and general replacement for the old Calendar class, but exactly which java.time class to choose depends on your more precise requirements. Please go through the classes or a tutorial and pick the one that is right for you. One of the many advantages of ZonedDateTime over Calendar is that you get readable output when you print it.
To convert to a Calendar that you can pass to your legacy API:
Calendar calTwo = GregorianCalendar.from(zdt);
Tutorial link
Oracle tutorial: Date Time explaining how to use java.time.
I want to know a best practice of dealing with timezone in web app.
Let take an example, Server is in UTC timezone, user1 and user2 both are in different time zone. what is a proper way to deal with date?
When user1 add a new date it is in different timezone and Server is in UTC so should I convert date to UTC and store in database?
When displaying date fetch date which is in UTC format and then convert it according to client timezone and show it. Is it proper way?
What is DST issue? is it effect this process?
Somewhere I read that store date in mili seconds only is it good idea? right now I store as a date/time.
is there any proper method or library to do this please suggest
My issue is
client with GMT +5:30 create a record and set delivery date and time let say june 30 2014 11:30 PM GMT +5:30
So Transporter with GMT -3:00 can see a exact local time in GMT -3:00 which client select. How to achieve this ?
1
Yes. Usually best practice is to store all your date-time values in UTC. Your business logic should work in UTC.
You may want to also store the value input by user or outside data source as an audit trail or debugging aid. But use UTC for the official record.
Yes the server's time zone should be set to UTC (or, if not possible, use Reykjavík Iceland). But do not depend on this in your programming. Specify your desired time zone in your code rather than rely on defaults.
2
Yes. Convert to a localized time for presentation. Unless, of course, the user prefers UTC.
Think of it as part of localization. When you internationalize, you work with key values in your code. Then upon presentation, you use the key value to look up a localized translation string to display to the user.
3
Non-issue. If by "DST" you mean Daylight Saving Time, the use of a decent date-time library will automatically handle adjustments for DST. Caveat: you need to keep the time zone definition list used by your library up-to-date as governments frequently change the rules.
If adjusting for DST (or time zones) causes confusion or misinformation with your users, then you should be displaying UTC in that case.
4
No. Do not store or work with milliseconds in most cases. Databases and date-time libraries may do so internally, but you should not.
Some nerdy types will suggest tracking milliseconds. But working with date-time as milliseconds is like working with text as byte arrays. We use libraries of code with higher levels of abstraction to handle all the complexities of text (UTF-8, Unicode normalization of diacriticals, etc.) and add helpful methods (search, replace, etc.). So it is with date-time.
Furthermore, using milliseconds will cause confusion and make debugging difficult as you cannot readily make sense of their value. Date-time work is inherently tricky and error-prone. Using milliseconds does not help.
And not all databases and other libraries use milliseconds internally. Some use whole seconds, or microseconds, or nanoseconds. Nor do they all use the same epoch.
5
In Java we have two good date-time libraries: Joda-Time and java.time (Java 8).
The java.time package was inspired by Joda-Time but is re-architected. They share similar concepts, but are not identical. You can use both in your code as long as you are careful with your import statements. Both have their own strengths and weaknesses.
Avoid j.u.Date/.Calendar
Do not use the java.util.Date and .Calendar classes bundled with Java. They are notoriously troublesome, flawed both in design and in implementation. They have been supplanted by Sun/Oracle with the new java.time package.
Both Joda-Time and java.time include handy methods to translate to/from a java.util.Date object for when some other class requires a j.u.Date object.
Bonus Tips
Regarding text formats:
Avoid that string format you used in your question. It is unwieldy and difficult to parse.
Learn about using various string formats defined by the ISO 8601 standard for textual representations of date-time values.
Do not drop that leading zero in the offsets, as you did in your question. That will break code in libraries, and violates standards requirements. Always write +05:30, never +5:30. Make that a habit even when writing prose, not just in your programming code.
Example Code
Example code with Joda-Time 2.3.
Instantiate the date-time, local to a +05:30 offset. I arbitrarily chose Kolkata time zone. You would replace with appropriate one of course.
DateTimeZone timeZoneKolkata = DateTimeZone.forID( "Asia/Kolkata" );
DateTime dateTimeKolkata = new DateTime( 2014, DateTimeConstants.JUNE, 30, 23, 30, 0, timeZoneKolkata );
Adjust the same moment to another time zone with a -03:00 offset. I arbitrarily chose America/Buenos_Aires.
DateTimeZone timeZoneBuenos_Aires = DateTimeZone.forID( "America/Buenos_Aires" );
DateTime dateTimeBuenos_Aires = dateTimeKolkata.withZone( timeZoneBuenos_Aires );
Convert to UTC.
DateTime dateTimeUtc = dateTimeKolkata.withZone( DateTimeZone.UTC );
I want to get the timezone shortcut like EST (for eastern standard), PST (pacific), and so on based on the UTC offset. I realize it's not a simple problem and there can be more than one location based on a particular offset, but that's okay.
I'm trying to get it using Util Calendar object but I don't seem to get a string but rather just the offset.
public String foo(int offset)
{
....
return TimeZoneShortcut;
}
Thanks in advance.
The answer by user2580516 is correct. I can add a bit more.
Avoid Three-Letter Codes
The three-letter time zone IDs are neither standardized nor unique. Avoid them.
For example, IST is used to mean India Standard Time or Irish Standard Time. There are many such collisions.
Time Zone Names
Instead of 3-letter codes, use proper time zone names. Examples: "Europe/Paris", "America/Montreal", and "Asia/Kolkata".
There does not seem to be an official standard for time zone names. That surprises me; hopefully I'm wrong and someone can fill me in. At any rate, a commonly used list is take from the tz database (formerly known as the Olson database), as listed in this Wikipedia page.
The excellent date-time library, Joda-Time, has a method to generate a list of its currently known time zone names.
The time zone names change over time, some are added, and their rules change too. All that is determined by politicians and bureaucrats, so changes are last-minute and not always sensible. So you should take care to keep your date-time library up-to-date, or at least update its contained time zone database.
Impossible Question – Cannot Determine Time Zone
A time zone is more than just an numerical offset from UTC/GMT. A time zone also contains the set of rules for Daylight Saving Time (DST) and other anomalies.
So you cannot infer a time zone from an offset. You can guess, but you cannot be sure.
For example, take the offset of +01:00. Is that "Europe/Paris" or "Africa/Lagos"? Both have an offset of one hour ahead of UTC. So does it matter which you use? Yes… France observes Daylight Saving Time but Nigeria does not. Assigning the wrong time zone means your date-time calculations will be wrong.
Another twist… Perhaps that +01:00 was recorded in London during the summer time. In summer, London observes DST and moves its clocks 1 hour ahead. While standard time there is +00:00 (on UTC/GMT), DST moves them one hour ahead of that.
Yet another twist… Even if you say "just pick one", which one? For +00:00 in just standard time, there are at least 2 three-letter codes (CET and MET) and 37 named time zones crossing two continents.
Perhaps you are thinking, "I can use the date to figure out if DST was in effect". Nope, DST starts and ends on different dates in various time zones sharing the same offset. Furthermore, some countries (time zones) are sensible enough to not fool with DST.
So regarding your question being "not a simple problem … but that's okay" is wrong. It's not a problem, it's impossible. Like the question, "Given a birthday, determine an individual person". You can determine that a person or time zone is not correct, but you cannot determine which is correct.
Record Time Zone With Time
If knowing the time zone (its locality and rules) is important to you, you must record the zone information along with the date-time. This may mean an extra field in your database for example.
Java 8 brings a new java.time.8 package, inspired by Joda-Time, defined by JSR 310. The designers have come to realize the importance of the time zone as a part of a date-time value. As a result, their designs include:
The main date-time class starts with the word "Zoned" to stress that the class includes time zone info: ZonedDateTime
Their toString implementation on the ZonedDateTime class extends the ISO 8601 format by appending the name of the time zone in brackets. Instead of:2014-02-14T20:51:55.427-08:00it outputs2014-02-14T20:51:55.427-08:00[America/Los_Angeles]
Use TimeZone.getAvailableIDs(), and select one (maybe the first) that has only three letters. You'll have to adjust the offset to numeric milliseconds to pass into that function. Use of the three letter IDs is deprecated, but it sounds like you are okay with that.
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".