How to translate between windows and IANA timezones in java - java

I need to translate between IANA timezone & windows timezone & vice-versa. There is another question reported: How to translate between Windows and IANA time zones?
It specifies that Noda time library can be used in .Net
Do we have any library to be used in Java? Or any other utility to be used in java?

This may be what you need, but I don't know if it will work for all your use cases:
for (String tzId : TimeZone.getAvailableIDs()) {
TimeZone tz = TimeZone.getTimeZone(tzId);
if (tz.getDisplayName(Locale.ENGLISH).equals("Eastern Standard Time")) {
System.out.println("tz = " + tzId);
}
}

I have implemented support for Windows zones in my Java-library Time4J. The last version v4.2 is also interoperable with Java-8 so it is easy to convert all basic Time4J-types to java.time-equivalents. For example recognizing Windows zones as strings is possible in constructing as well as during parsing:
// conversion Windows to IANA
WindowsZone wzn = WindowsZone.of("Eastern Standard Time");
TZID winzone = wzn.resolveSmart(Locale.US);
System.out.println(winzone.canonical()); // WINDOWS~America/New_York
// usage in timezone calculation
Timezone tz = Timezone.of(winzone);
System.out.println(Moment.UNIX_EPOCH.toZonalTimestamp(winzone)); // 1969-12-31T19
// usage in parsing and formatting
ChronoFormatter<Moment> f =
ChronoFormatter.ofMomentPattern(
"MM/dd/uuuu hh:mm a zzzz", PatternType.CLDR, Locale.US, winzone);
Moment pacificTime = f.parse("07/17/2015 02:45 PM Pacific Standard Time");
System.out.println(f.format(pacificTime)); // 07/17/2015 05:45 PM Eastern Standard Time
As you can see, a locale Information is necessary to map a Windows zone like "Eastern Standard Time" to an Olson/IANA-identifier like "America/New_York". The underlying data and mapping informations are taken from CLDR.
The reverse way from IANA to Windows might be done this simple way:
String iana = "America/New_York";
String winzone = "WINDOWS~" + iana;
NameStyle dummy = NameStyle.LONG_STANDARD_TIME; // does not really matter
String name = Timezone.of(winzone).getDisplayName(dummy, Locale.US);
System.out.println(name); // Eastern Standard Time
However, this reverse conversion might not work for all iana-identifiers because Windows only supports a very simplified subset of timezones compared with IANA-TZDB. I also think that the reverse way is hardly used in practice. Users should rather work with IANA-timezones by default and only use Windows timezones if that is the (unavoidable) input to handle (see first part of my answer).

I finally had to make my own implementation. The windowsZones.xml needs to be updated for plenty of missing timezone entries. I'm not publishing the updated file as there are many timezones where there is no perfect match between Windows offset & IANA offset.
Also, as for one Windows timezone there could be multiple IANA timezone. So, i had to make implementation to choose best suitable according to other information available like geography of user(address) etc.
With this, I'm just using the windowsZones.xml to get IANA timezone from Windows timezone & vice-versa.

Related

Time zone of a country, whether day light savings is in effect

Consider the below code:
if(strTimeZoneCd.equals("A"))
locTz = TimeZone.getTimeZone("AST");
else if(strTimeZoneCd.equals("M"))
locTz = TimeZone.getTimeZone("MST");
else if(strTimeZoneCd.equals("P"))
locTz = TimeZone.getTimeZone("PST");
else if(strTimeZoneCd.equals("H"))
locTz = TimeZone.getTimeZone("HST");
else if(strTimeZoneCd.equals("C"))
locTz = TimeZone.getTimeZone("CST");
else if(strTimeZoneCd.equals("E"))
locTz = TimeZone.getTimeZone("EST");
else if(strTimeZoneCd.equals("G"))
locTz = TimeZone.getTimeZone("GMT");
else if(strTimeZoneCd.equals("Y"))
locTz = TimeZone.getTimeZone("AKST");
Here if I am passing A, it will give me AST. But instead of that I need to determine if I should return AST or ADT.
I need to determine if AST is under daylight saving now. If it is under daylight saving, I can return ADT and if it is not I can return AST. But I am not getting how to determine whether that timezone is under daylight saving or not.
Can someone please help me?
First of all, avoid using the short abbreviations for timezones names (like CST, PST or CEST) because they are ambiguous and not standard.
CST, for example, is used by more than one timezone: it can be "Central Standard Time", "China Standard Time" or "Cuba Standard Time". And each one has different rules regarding Dayligh Saving Time, so using the abbreviation might not necessarily get the results you expect.
The TimeZone class assumes some defaults for those short names (all arbitrary choices, as any default is) and also has the bizarre behaviour of returning GMT when the name is unknown.
To avoid those ambiguities, it's better to use IANA timezones names (always in the format Region/City, like Asia/Kolkata or America/New_York).
You can get a list of available timezones (and choose the one that fits best your system) by calling TimeZone.getAvailableIDs().
Then you can use the inDaylightTime() method, as already explained in the other answers.
Another alternative is to use a formatter, because it checks automatically if it's in Daylight Saving Time and prints the zone short name. I also use a java.util.Locale to indicate that the names should be in English (I'm not sure if different languages affect the short zone names, it's a "just in case" approach):
// formatter with `z` (zone short name)
SimpleDateFormat sdf = new SimpleDateFormat("z", Locale.ENGLISH);
// set timezone in the formatter
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
// prints the zone name for the current date
System.out.println(sdf.format(new Date()));
The code above prints EDT (because today, September 13th 2017, New York is in Daylight Saving Time and the abbreviation used is EDT).
In this case, you could create the formatter, and use your if logic to set the correct timezone in it. Then, the formatter takes care of checking if the date is in Daylight Saving Time, returning the correct abbreviation.
Java new Date/Time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
First I create a DateTimeFormatter with the z pattern (that corresponds to zone short name) and English locale.
Then I use a ZonedDateTime, which represents a date and time in a specific timezone, and the now() method to get the current date/time. I also use ZoneId to especify the timezone I want:
// create formatter for short zone name and English locale
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("z", Locale.ENGLISH);
// format current date in New York timezone
System.out.println(fmt.format(ZonedDateTime.now(ZoneId.of("America/New_York"))));
This also prints EDT as well. You could apply the same if logic above to define which timezone will be used in ZoneId.of(). Just remind to not use the short names (CST, etc), because the new API is not so lenient as the old one.
TimeZone assumes lots of arbitrary defaults and returns "GMT" when the zone doesn't exist, but ZoneId will throw an exception if you try to get an invalid zone (some abbreviations should work for retro-compatibility reasons, but the defaults are arbitrary as well, and you should avoid them).
Custom map of zone names
You can optionally create a custom map of timezone names, so you don't need to make lots of if clauses to determine the corresponding zone. Something like this:
// create custom map of zone names
Map<String, String> customZones = new HashMap<>();
// map "E" to New York
customZones.put("E", "America/New_York");
// map "G" to GMT
customZones.put("G", "GMT");
...
// create timezone using the custom map ("E" will create "America/New_York" zone)
ZoneId zone = ZoneId.of("E", customZones);
// format current date in specified timezone
System.out.println(fmt.format(ZonedDateTime.now(zone)));
work around this:
For any particular TimeZone
TimeZone tz = TimeZone.getTimeZone("EST");
boolean inDs = tz.inDaylightTime(new Date());
You can use this program to determine whether that timezone is under day light saving or not.
Also see this link.
TimeZone.getTimeZone("CST") returns GMT
import java.util.Date;
import java.util.TimeZone;
public class test {
public static void main(String[] args) {
System.out.println(TimeZone.getTimeZone("EST").inDaylightTime( new Date() ));
System.out.println(TimeZone.getTimeZone( "GMT-9:00").inDaylightTime( new Date() ));
}
}

Handling date/time in java/android and daylight savings

I am making a diary application for Android and I want to allow the user to select the timezone they are in. Time has always been a area of confusion for me programatically.
I am going to create an enum for the available timezones.
I am going to save date/time entries to a sqlite in long UTC format, then handling offsets and DST programmatically in Java for display purposes.
I am actually aware of Java's limitations when it comes to date/time handling.
Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC")); //returns the current time in UTC format
Long utcLong = utc.getTimeInMillis(); //returns current utc time in long for database insertion
Question 1: How would I apply an offset to it and account for when to apply any additional DST offsets? Because not all timezones observe DST and DST comes into effect at different dates for different timezones.
Question 2: Java's TimeZone class has something like ~800 ids, it would be annoying to the user to have to scroll through ~800 options to find the one that applys to them. Is there a short list available? I'm thinking there are around ~50 useful timezones.
First of all, I recommend you to not use the Calendar class. It's outdated and has lots of bugs and design issues. This terrible API was replaced by much better ones:
for Java >= 8, use the new date-time API
for Java <= 7, use the ThreeTen Backport
for Android, you can also try ThreeTenABP
The code below works for all, the only difference is the package names (in Java 8 is java.time and in ThreeTen Backport is org.threeten.bp), but the classes and methods names are the same.
To get the UTC current date/time, the best choice is to use Instant class:
// current date/time in UTC - now() always returns the current instant in UTC
Instant instant = Instant.now();
System.out.println(instant); // 2017-06-03T18:03:55.976Z
// equivalent to calendar.getTimeInMillis(), it returns a long
System.out.println(instant.toEpochMilli()); // 1496513035976
To convert this instant to a timezone, you can use the ZoneId with a ZonedDateTime:
// ZoneId accepts the same IDs used by TimeZone
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// convert instant to timezone
ZonedDateTime z = instant.atZone(zone);
System.out.println(z); // 2017-06-03T15:03:55.976-03:00[America/Sao_Paulo]
// converts back to UTC (returns an Instant)
System.out.println(z.toInstant()); // 2017-06-03T18:03:55.976Z
The code above already takes care of DST changes, so the conversion from and to UTC is straightforward.
Timezone list
You say that you have a list of ~50 "useful" timezones. I don't know what criteria you used to define that list, but what happens if an user is in a timezone that's not in the list?
There are some ideas of timezone-picking user interfaces in this link and here. You can choose one and adapt to your app.
I also suggest to not use (if possible) the 3-letter timezone abbreviations (like CST or PST) because they are ambiguous and not standard. It's better to use the full names (like America/Sao_Paulo or Europe/London) as they are the ones used by Java's APIs (you can get the full list with ZoneId.getAvailableZoneIds()) and they are configured with all DST changes for each zone.

Create java.util.Date from C# System.TimeZone

I have a Java service which needs to return date/time information that is formatted relative to a user's current timezone (C#). For example, say a user is on the west coast (pacific time) where it is 8:00pm. They connect to a service that is hosted in the midwest (central time) where it is 10:00pm. If the user were to ask the server for the current time, the server should respond, "8:00pm" for the user.
My thought is that the client application (C#) will pass information to the service about its current timezone or UTC offset. Java will then create/format all dates using that timezone.
However, I am having trouble finding a good way to pass C# System.TimeZone information in a way where Java can create and use a java.util.TimeZone object. I can get the UTC offset from C# but not a three digit timezone code. In Java I can create a TimeZone from a three digit code but can't find a way to create one from a UTC offset. From everything I've seen in Java, TimeZones are created with a code ("PST") or country/region ("America/Los_Angeles"), and I don't believe there is a clear way to get the timezone in this format in C#.
How might this be accomplished?
Work In UTC
As the comment suggested, usually the best way to go is to work your business logic in UTC. Adjust into a local time zone only for presentation when expected by a user.
So your Java backend should be returning a UTC date-time value. Usually the best way to do that is to serialize the date-time value as a string in the standard ISO 8601 format. Then let the client app handle the presentation by generating a string representation of the date-time value adjusted into a particular time zone.
See this Question about best practices for date-time work.
But somehow this is not feasible in the context of this Question. So the client app needs to communicate to the backend the desired/expected time zone.
Time Zone
Avoid the 3-4 letter codes such as EST or IST. These codes are neither standardized nor unique. Furthermore they invoke Daylight Saving Time in a confusing way.
Instead use official time zone names. These are mostly in the format of "continent", slash, and "region/city" in English, such as America/Montreal or Asia/Kolkata.
.Net Fails To Support Proper Time Zone Naming
Unfortunately, it looks like the .Net team did not know about proper time zone naming.
The System.TimeZone class offers properties such a StandardName. But the examples in the System.TimeZone doc show "Pacific Standard Time" rather than a proper name such as "America/Los_Angeles".
Noda Time
My first suggestion is to consider using the Noda Time project, an alternative date and time API for .NET. It was inspired by the highly successful Joda-Time library in Java, which in turn inspired the new java.time framework built into Java 8 and later.
Looks like Noda Time has support for proper time zones. Rather than use System.TimeZone, use Noda Time to obtain the time zone information.
Roll Your Own Mapping
If Noda Time is not an option, then I might look to see if my users are all in a few time zones. If so, I would make my own mapping of such as "Pacific Daylight Time" returned by C# the standard name for a time zone being the proper name "America/Los_Angeles".

Java time zone display string (GMT-06:00 vs. CST) on Windows

Java application writes events to a log file, including a timestamp (as returned from Date.toString()), which in turn includes the time zone. On the Windows machines I use, I see the string returned by Date.toString() having the time zone represented as a three-character string (e.g. "CST"). But on some customer machines, the dates are being written to the log file with the time zone represented as an offset from GMT (e.g. "GMT-06:00").
We have a tool that parses the text of log files for various pieces of information, but unfortunately, its original implementation assumed the three-character representation and won't work on those log files that have the GMT-offset representation. We've fixed the tool to be indifferent to that now, but we'd like to be able to advise customers who are running an old version and are having this problem due to their strings having GMT-offset time zones, that they can get the tool to start working if they change their system settings so that their logs files are written with three-character string time zone strings going forward. Additionally, we'd like to account for this variability in our future test plans, ensuring that we test things using each setting. But I haven't been able to determine just what in Windows setting tells Java to use "CST" vs. use "GMT-06:00".
I see a couple of time-zone related registry settings, but nothing that I can clearly identify as controlling that particular choice. Some of the registry settings refer to tzres.dll. Is the choice baked into that? Is there any simple way on Windows to get Date.toString() to formulate its string using one time zone representation vs. using the other?
I don't know the exact cause of this difference in behavior, but I can guess. A time zone is an offset from UTC and history & info about anomalies for that particular are such as Daylight Saving Time. Some machines (or the JVM default) may be set to only an offset rather than a specific named time zone.
The java.util.Date class is notoriously troublesome in general, and should be avoided. Specifically, the toString is terrible in two ways. (A) The format it uses to generate the string is bad, as you have discovered. (B) the JVM's default time zone is applied. That application causes confusion as it implies a Date has a time zone when in fact it does not. This method should only be used temporarily for quick-and-dirty purposes, never for logging.
Use a decent date-time library. That means either Joda-Time or the new java.time package in Java 8. Both use the sensible and useful ISO 8601 format by default.
Generally best practice is to do your logging in UTC time zone (no offset).
Example: 2014-05-04T10:36:34Z
To generate such a value in Joda-Time:
String output = new DateTime( DateTimeZone.UTC ).toString();
If your question is, "How do I change the time zone used by a JVM running an app I cannot alter?", one solution is setting the JVM's time zone by passing an argument when launching the JVM. See this question.

TZ Var to Java TimeZone?

I need to convert from the Unix TZ environment variable of the form:
stdoffset[dst[offset][,start[/time],end[/time]]]
into a Java TimeZone object.
For example, convert AEST-10AEDT-11,M10.1.0/02:00:00,M4.1.0/03:00:00 into a Java TimeZone object that represents "Australia\Sydney". Before I go and write the code myself I'd like to know I'm not inventing the wheel again, so does anyone know if there's a library already available that can do this?
It will be really hard to write such a conversion program. On Unix, you can have customized daylight rules and Java provides no such facility. It's possible to search through tzfile trying to find a match but you have to convert the TZ rule into the format used by tzfile, an enormous task.
Why don't you use the same zone id used in Java? For example, you can set TZ as,
export TZ=Australia/Sydney
This is supported on most modern Unix systems (like Linux, Mac OS X). Search /etc/zoneinfo or /usr/share/zoneinfo. If you can find a file for your timezone, the ID will work.
I also started on a custom TimeZone to handle the old TZ format but I was able to convince the sysadmin to use the zone id so I didn't finish it. The difficult part is to implement the useDaylightTime() because the rules used in TZ is very complicated.

Categories