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".
Related
I'm including timezone identifiers as strings, in data that's being stored in Google Cloud DataStore, and I want to get the current time offset from UTC (including any adjustment for daylight saving time), for that timezone identifier. For example I want to return something like -08:00, or +6:00
The identifiers I'm using are the (Supported Time Zone Values) (these appear to be timezone identifiers defined by Trifacta, which is a partner of Google that provides data prep capabilities) - the Google documentation appears to be a dupe of Trifacta's own documentation - https://docs.trifacta.com/display/SS/Supported+Time+Zone+Values.
The Google documentation says this in relation to the Supported Time Zone Values:
For the functions that support use of specified time zones, you can
apply the [Supported Time Zone Values] as parameters to specify the time
zone
So, I'm wondering if there might be functions (either in Java, or in GQL) that will accept a Supported Time Zone Value and return an offset, or allow it to be derived? For example I'm wondering if there's something available in Trifacta or GQL that's like the AT TIME ZONE in SQL Server 2016.
How can I return the current offset to UTC based on the Supported Time Zone Value?
The only GCP product that uses the Supported Time Zone Values afaik is Cloud Dataprep by Trifacta. The time zone values are taken by functions NOW and TODAY. In java, you can take a look at ZoneOffset class, but I'm not sure if you can incorporate all the identifiers form Trifacta.
if I understand correctly you are trying to modify most current dates at your timezone based on an offset. This is achievable with the combination of functions using NOW and DATADD in Trifacta.
Refer the article here to get more clarity on this https://community.trifacta.com/s/article/Function-NOW-DATEADD-and-DATEDIF
Best
Vardan
Quick summary of my issue first, then details further below.
I have a Calendar date with 00:00:00 as the time as it's not important to the business. This value is sent to a webservice which generates a XML in which the value ends up in the following format : 2014-09-12T07:55:07.000Z. I have noticed that this is the original value converted to a +0 timezone (UTC) (ours is CET, +1, but currently CEST, +2, because of DST).
I currently have no idea whether the system reading the XML takes timezones into account or would extract 2014-09-12 and assume it's in the +2 timezone.
What I've noticed is that sending "2014-09-12 00:00:00" local time (tz +2) ends up as 2014-09-11T22:00:00.000Z in the XML. No big surprise, it converted it... but if it's interpreted as is by the other system, it will think the date is a day earlier than it should be.
What can be done to ensure this gets interpreted as intended?
I was thinking of using noon instead of midnight to make sure timezone shifts wouldn't impact interpretation, but it feels like a dirty trick. Or maybe I should cheat and have the Calendar timezone be +0 so it's not time-shifted when put in the XML?
Q&A
Why do you "send a Calendar to a webservice"?
The application is in Coldfusion 7. To communicate with SOAP webservices, the server generates a set of Java classes that fit the definition of the argument expected by the webservice. The argument is apparently a single big object with a lot of attributes and sub-attributes. So one instantiates the main Java class and uses setters and further instanciations of other classes to "fill out" all the attributes.
Do you have to use Calendar?
Yes, the Java object definition cannot be changed. It expects Calendar for all dates.
What's this 2014-09-11T22:00:00.000Z format?
I have no idea. This seems to be what the end system expects for dates.
You should use JODA
Unless JODA classes extend Calendar and are compatible with Java 1.3 (current Java version on the Coldfusion server -- yes it's old), I doubt it will work.
How much can you do on the other system?
The other system is the responsibility of a different team and is apparently very hard to change. I expect the solution will have to be found on the side of our application.
Although the time value in your Calendar object is not important to your business, it is important to the webservice that you use and have no control over. The calendar object specifies an instant in time, so you must make sure that instant is in the day that is important to you. I recommend you use midday, as you suggested already. I also recommend that you create your Calendar object in the UTC timezone:
Calendar myCalendar=Calendar.getInstance(TimeZone.getTimeZone("UTC"));
I have a server that is being fed data from clients in different timezones. The data feed contains people, their date of birth and other dates of events. For our purposes, it would be convenient if we could just store the dates as their given to us.
For example, if the client is in California and it tells us the person's date of birth is May 31st, we'd like to store it in the database as May 31st 1999, pacific time. This way, no matter what timezone you're in, you can see that the person was born on May 31st.
At the same time, we want to be able to query this data to be able to figure out things like, "Is this person a minor" or "did this event happen less than 24 hours ago?
The clients are sending us data over a http based rest API. The server is written in Java (using eclipselink). The database is postgresql. Is it possible to satisfy these requirements?
Typically, people say to store everything as UTC, but I feel like that would be a bad idea because we'd lose the timezone of the original data.
UTC is the way to go. For timestamptz (timestamp with time zone) the time zone of input values only serves as modifier for Postgres to calculate UTC internally. (For timestamp [without time zone] any appended time zone would be ignored!). The time zone is not saved. You need to save it additionally to know where in the world something happened.
If you do that, you might as well store local timestamps. Just don't get confused which is which. Either convert everything to UTC (happens automatically for timestamptz), or convert everything to local time (define "local": your local? local to the db server? local to the user?).
In particular, rather store the exact time zone name (or a reference to it) than just "pacific time". This is more exact for daylight saving time, leap seconds or other events.
Detailed explanation:
Ignoring timezones altogether in Rails and PostgreSQL
About time zone names and abbreviations:
Time zone names with identical properties yield different result when applied to timestamp
About time zone handling:
Accounting for DST in Postgres, when selecting scheduled items
Preserve timezone in PostgreSQL timestamptz type
The answer by Erwin Brandstetter is 100% correct.
Calculating Age
As for matters such as calculating age of a minor, that is a bit tricky because of time of day. Using the Joda-Time library, you can call the method withTimeAtStartOfDay to set a DateTime object to the first moment of the day. Usually that first moment is the time 00:00:00 but not always because of Daylight Saving Time or other anomalies. Ignore the "midnight"-related classes and methods as they have been supplanted by the above-mentioned method.
Furthermore, to be really accurate about age to cover yourself legally, you might want to calculate age as the first moment of the day or two after the birth date-time. Unless you know their time of birth and the time zone of that birth, you cannot know exactly their age.
Avoid j.u.Date/.Calendar
The java.util.Date and .Calendar classes bundled with Java are notoriously troublesome. Avoid them. Use either Joda-Time and/or the new java.time package bundled in Java 8 (inspired by Joda-Time but re-architected).
Unlike java.util.Date, the date-time objects in both the other libraries know their own assigned time zone. A j.u.Date is particularly confusing because, while it has no time zone assigned, its toString method applies the JVM’s current default time zone thereby creating the illusion of an assigned time zone.
Joda-Time | java.time
With Joda-Time and java.time, things are much clearer. You specify a time zone to each date-time object (otherwise the JVM default is assigned). You can easily convert from one time zone to other.
Both libraries use immutable objects, where a new object based on the original is created rather than changing (mutating) the original.
You can call getZone a Joda-Time DateTime object to obtain its time zone name (ID) and its offset from UTC for your records if you deem that important.
ISO 8601
Learn about the ISO 8601 standard for sensible String formats of date-time values. Consider using those in your text-based API. ISO 8601 is now the norm for all new Internet protocols. Ex: 2014-08-13T16:02:01Z or 2014-12-22T11:54:23+04:00.
And use proper time zone names. Avoid the 3 or 4 letter codes as they are neither standardized nor unique.
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.
I'm setting the standards for our application.
I've been wondering, what default date format should I choose to use ?
It should be:
Internationalization & timezone aware, the format should be able to represent user local time
Can be efficiently parsed by SimpleDataFormat (or alike, jdk classes only)
Programming Language agnostic (can parse in java, python, god forbid C++ :) and co.)
Preferably ISO based or other accepted standard
Easy to communicate over HTTP (Should such need arises, JSON or YAML or something in this nature)
Can represent time down to seconds resolution (the more precise the better, micro seconds if possible).
Human readable is a plus but not required
Compact is a plus but not required
Thank you,
Maxim.
yyyy-MM-ddThh:mmZ (See ISO 8601) You can add seconds, etc
You can read it easily, it will not be a problem for SimpleDateFormat.
The most canonical and standard form is probably "Unix Time": The number of seconds elapsed since midnight Coordinated Universal Time (UTC) of January 1, 1970.
If you set that as the default time-format you can easily parse it, store it in memory, write it to disk, easily communicate it over HTTP and so on. It is also definitely an accepted standard, and in a sense it is "time-zone aware", since it is well-defined regardless of time-zones.
(This is the format in which I always store all my time stamps; in databases, in memory, on disk, ...)
The "right" default format really depends on what you're doing with it. The formats for parsing, storing, and displaying can all be different.
For storing the date you're (almost) always going to want to use UTC as aioobe says, even when you want to display it in user local time. I say "(almost)" but I really can't think of a case where I would not want UTC for a saved date. You may want to store the TZ information for where the date originated also, so you can report it in that local time, but more often you want to display the local time for the whoever is currently looking at the date. That means having a way to determine the current user's local time regardless of what the original local time was.
For displaying it, the "default format" should usually be determined by the viewers locale. 08/09/10 usually means 2010-Aug-9 in the U.S. ("Middle endian") but normally means 2010-Sep-8 in most of the rest of the world ("Little endian"). The ISO-8601 format "2010-09-10" is safe and unambiguous but often not what people expect to see. You can also look over RFC-3339 for Date and Time on the internet and RFC-2822 for message format (transmitting the date)
For parsing a date, you'll want to parse it and convert it to UTC, but you should be fairly flexible on what you accept. Again, the end users Locale and timezone, if discoverable, can help you determine what format(s) of string to accept as input. This is assuming user-typed strings. If you're generating a date/time stamp you can control the form and parsing will be no problem.
I also second BalusC link which I hadn't seen before and have now favorited.