I need to find time based on the province/postal code.
For a given province I need to get current time in that province.
Approach 1: I preparing a mapping between province and timezoneId
like "AB" - "Canada/Atlantic"
And TimeZone timeZone=new TimeZone("Canada/Atlantic");
Problem is I don't have such mappings.
Can you please suggest me better way to find the time based on the province/postal code
You can't get a 1 to 1 or n to 1 mapping between provinces and time zones (http://www.timeanddate.com/time/canada/time-zones-background.html). Like the USA, some jurisdictions are split between time zones. You will need additional geographic data. Have you thought about adding a time zone field to your database? For example, instead of asking for a user's province and then trying to guess what their time zone is, just ask the user for their preferred time zone.
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 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.
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.
Application: Java + ExtJS
There are a lot of different entity with properties of java.util.Date type: startDate and iesendDate (endDate could be NULL). Both dates could be selected with or without time part (e.g. time part is always persisted, event if it is not selected). For example, like this:
2010-07-01 00:00:00
Possible problems start when user selects endDate without time. For example, period starts on 2010-07-01 and ends on 1010-07-04. Right now in database it is stored like:
startDate="2010-07-01 00:00:00"
endDate="2010-07-04 00:00:00".
So it seems that period ends on the FIRST second of 2010-07-04. But as user assume, that endDate is implicitly included, e.g. period ends on LAST second of 2010-07-04. There are a lot of date comparisons for different periods in the system.
How in this case to store end date properly?
I thought about possible solutions, but all of them seems a bit wrong:
To store time part for end date like this: "2010-07-04 23:59:99". But then seems that end date day is not 24h - but (24h - 0.(9) millisecond), that could be potential problem. Also time part looks quite ugly.
To modify ExtJs component that it will add 1 day to date selected by user on persistance stage and substract 1 day again when this date will be shown to user (except cases when the user explicitly set time part). I don't like here that dates with time part and without it are treated differently.
To save only start date as Date object, and then save length of period in seconds, for example. This approach seems quite good - but a have to rework the whole application and possible it will be no very easy to use different comparisons on end dates.
Just use current one - save non-enclusive end date without time and be very careful during dates comparisons
Could someone explain the most widely used practices to solve such problem?
I've recently changed from your first approach to your second approach.
Approach 1: "2010-07-04 23:59:99" should be "2010-07-04 23:59:59" but anyway it is indeed ugly and technically there is a lost second. Another issue I did have is that I wanted to start one record with the same data/time as another record was stopped. So it was possible to find the successor of a record. And with approach 1 this cannot be done as the time will differentiate 1 second.
Approach 2: The end date will be "2010-07-05" and the query condition will be < endDate instead of <= endDate for approach 1. Here the end date is meaning 'till' or 'until' or 'up to' and not like in approach 1 'up to and including'. For this reason in new projects I do use tillDate or actually I use something like serviceStart / serviceTill.
The disadvantage is indeed to format it -1 day when showing to the user. But for me this makes sense.
Add end date as +1 day of user selected value.
Separate model and presentation
Do separate the stored end time in your database completely from the presentation of the end time to the user.
Store end date and time in database: Since you always store both date and time, you should clearly store the true date and time. If the period end at midnight between July 4 and 5, store this time, so 2010-07-05 00:00:00.
Present to the user: How your user would like to see that end time, I cannot say, and you should ask the users themselves. Maybe they will tell you:
As it is. 2010-07-05 00:00:00.
As 24 hours on the last day of the period, 2010-07-04 24:00:00.
As the last day as date only 2010-07-04 (I consider this unlikely, especially of the start time is not at midnight).
Or something else.
So yes, it’s very likely that you will have to treat end at midnight specially for presentation. It is not nearly as bad as if you had needed to treat it specially in your business logic.
Hi I want to get currency name by GMT Time Zone. I got Time Zone and corresponding name of the time zone. The code is
TimeZone tz = TimeZone.getDefault();
String gmt1=TimeZone.getTimeZone(tz.getID()).getDisplayName(false,TimeZone.SHORT);
String gmt2=TimeZone.getTimeZone(tz.getID()).getDisplayName(false,TimeZone.LONG);
Log.d("Tag","TimeZone : "+gmt1+"\t"+gmt2);
Now I want to get currency name like if that time zone is Indian standard Time means that will be show the currency is Rupee.
Currency current=Currency.getInstance(gmt1);
String current1=current.toString();
System.out.println(current1);
I tried by this code but i can't get it. Anybody tell me what is the mistake on my code and how to do? Thanks in advance.
There is no reliable mapping of time zones or time zone names to currencies. Your current approach won't work in a lot of countries.
The issue with your above code is that the Currency objects takes either a 3-letter currency name as a string or a Locale object. In order to get this information you really need to know the country. Unfortunately a timezone does not give you specific enough information about the locale.
There are, after all a limited number of unique time zones, and by far more countries. For example, look at all the countries in Africa that are on a variant of UTC+1 (Wikipedia GMT article)
You'll need to come up with a country code in order to accomplish this.
Currency.getInstance takes an ISO 4217 currency codes as parameter, not a time zone name. Many countries can share the same time zone, you can't tell the local currency by the time zone someone is in.
Maybe you should use a locale as parameter (probably the user's default locale).