I am defining a schema for my web service that will be accessed from multiple countries. I am wondering which of the below 2 should be used (both are valid according to xsd dateTime type and ISO 8601) and which one of them is WS-I compliant?
UTC format like 14:15Z or 14:15:00Z. The appended Z letter indicates that the time is represented in UTC.
Alternatively, use a local time with explicit zone designation in one of the formats [+/-]hh:mm. Example: 12:15+02:00
It is somewhat subjective - both are OK. I prefer UTC. You likely need to convert the time to client local anyway (and you should rely on information from the client to do so, since the user may login from different timezones). When storing in UTC, you have to worry less about the details of how storage is taking place, since all times are represented in the same timezone and it is much easier to compare (and thus sort).
It depends on the use case. Sometimes it's useful to know the timezone the client is in. If the user enters a time of 13:00 in their timezone, they probably still want to see 13:00 when the retrieve the date.
Note, I'm not saying you store the time in local (which would be very bad of course), just that you may want to maintain the timezone.
Both forms compy with WS-I Basic Profile, as they are both valid lexical formats for xsd:dateTime.
Normally, a service description would specify xsd:dateTime in the schema and would not typically constrain the lexical format further. In this case the service implementation should be prepared to handle any valid xsd:dateTime value i.e. should be able to cope with either form in data received from clients.
If you really want to, you could restrict the allowed lexical formats in the schema for your service description, by defining a custom type based on xsd:dateTime with an additional pattern facet. This would still be WS-I Basic profile compliant, I believe, but I would avoid doing this unless you have a very compelling reason. In my experience custom types based on XSD types with added pattern facets do not always play nicely with all XML toolsets, so you may create problems for clients by adding additional constraints beyond xsd:dateTime.
Related
I have a scenario in a current java program where if the user enters a certain date (01/01/1900) in an excel Date field I'm supposed to flag that and clear the value out in the database. In this case since the field is a Date type, I need to pass it to an xml as "" i.e and empty String since I can't just pass null. I'm getting an error because it is expecting a format of "yyyy-MM-dd" to pass to the xml and not "". Of course when setting the Date field to a certain value, I can't just pass an empty String in the setVesselDate() method because it will complain saying it must be in so so format. I have a method that validates the date (handleValidateDate) that returns the sql Date value.
Any recommendation to actually set the date field as "" would be helpful. Below is the code I have:
if (vesselAssignmentObj.getVesselDate().length() > 0)
{
String clearOutDateFlag = "1900-01-01";
String clearField = "";
//below returns a dateformat of yyyy-MM-dd at i
vesselDate = handleValidateDate(vesselAssignmentObj.getVesselDate(), VESSEL_ASSIGNMENTS_VESSEL, i);
if (vesselDate.toString().equals(clearOutDateFlag))
{
vesselAssignmentObj.setVesselDate(String.valueOf(vesselDate.toString().equals(clearField)));
}
else
{
vesselAssignmentObj.setVesselDate(String.valueOf(vesselDate).toString());
}
}
No easy answer.
… I'm supposed to flag that and clear the value out in the database…
Whoever instructed you should have defined what "clear the value out" means.
NULL
Usually in a database "clear the value out" might mean using a NULL value. But nulls bring a bag of hurt, raising ambiguity as to the meaning, affecting sorting and queries in various ways, and carrying ramifications in your app(s) and libraries.
While I generally avoid NULL like the plague (taking Dr. Chris Date’s advice), this may in fact be the best fit for your needs.
Arbitrary date as flag
You could choose an arbitrary date to use as flag that means 'empty' or 'not specified' or 'unknown'. But what date? One commenter suggested 0000-00-00 but this value may exceed the limits of some database’s date data-types. Furthermore, dates around year zero can be problematic because of how different calendaring systems handle the meaning of that period. Furthermore, any date before the adoption of the Gregorian calendar in the West is problematic as we lost some days in transitioning from Julian calendar to Gregorian.
1901-01-01
In a comment you said that a business rules requires dates to be over the year 1900. In that case I would choose 1901-01-01 as my flag date. The trick is making this clear to the entire team and to posterity. Be sure to use well-named constant in your programming, and document well in both your apps and in the database.
1970-01-01
Another common choice of arbitrary date flag is the first of 1970, 1970-01-01. That date is a commonly used epoch reference date used in Unix time and in java.time. This makes that particular date recognizable to many folks in the information trade. But you still need to document thoroughly, as this epoch date is far from the only one: At least a couple dozen other epoch dates have been in widespread usage.
Millenium
Yet another choice could be the date of the new millennium. Unfortunately, that phrase means different dates to different people, in year 2000 or 2001.
The Postgres database uses 2000-01-01 as its epoch. The Apple Cocoa framework, possibly the most widely distributed software in the world, uses 2001-01-01.
Use objects, not strings
You should not be passing strings to/from your database. Use objects instead. The job of your JDBC driver is to mediate between your Java data types and your database types.
Drivers compliant with JDBC 4.2 and later should be able to use java.time types via PreparedStatement::setObject and ResultSet::getObject. If not, fall back to using the java.sql types briefly and immediately convert to/from the java.time types. To convert, look to new methods added to the old classes.
All this JDBC date-time stuff has been covered many times already, so search Stack Overflow for more information. Search for class names Instant, ZonedDateTime, and ZoneId.
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".
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"));
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.