joda-time: new DateTime(String) vs DateTime.parse(String) - java

Using the joda-time-2.0 version library, I was wondering, which of this functions is better to construct from an ISO date (suposed XML xs:dateTime format): new DateTime(String) versus DateTime.parse(String).
Because both return a different result from same value. Example:
new DateTime("2012-08-16T07:22:05Z")
DateTime.parse("2012-08-16T07:22:05Z")
Resulting different because of the ISOChronology. First says is ISOChronology[Europe/Paris] and second ISOChronology[UTC], although milliseconds are the same.
Also, here recomends to use ISODateTimeFormat.dateTimeNoMillis(), giving the same result as using the first version (new).

The two methods use two different conversion methods: the constructor uses an instance of InstantConverter, which in case of strings is a StringConverter and which doesn't yet support reading the timezone from the passed string, while the parse method uses a DateTimeFormatter which knows how to parse the timezone.
Although both formats in theory accept an ISO datetime format, I consider that the constructor is buggy since it always uses the system timezone instead of the one specified in the string. This is inconsistent with the other possible values accepted by this constructor, which do take into account a chronology with its timezone offset. For example, this constructor will return a DateTime object with the UTC timezone:
new DateTime(DateTime.parse("2012-08-16T07:22:05Z"))

Related

Get format pattern directly from a Date object in Java

I have a Date object but I don't know its format pattern. Is there some way to get the format pattern of a Date object directly from the object itself?
A java.util.Date object does not have an associated pattern. If you call Date.toString() it will return the Date as yyyy-mm-dd
You can also retrieve the format for a Locale by calling
DateFormat.getDateInstance(int,Locale)
The answer of #Sergio Montoro is only half-correct. In general, you have to make a difference between value-objects (here not in sense of J. Rose working on a new value type feature in Java-10 or later) and formatters.
A value object like java.util.Date can be formatted in many ways. This justifies the separation of value object and formatter. Hence value objects have no other built-in formats than what the method toString() inherited from class Object yields. Usually this method only serves for debugging purposes in best case.
This method toString() however uses following format pattern (correction of the other answer):
"EEE MMM dd HH:mm:ss zzz yyyy"
Important to note: This pattern itself is NOT part of the state of a java.util.Date-object. It is just the way how the method toString() works.
Maybe your question tries to target this format which has some very serious problems however.
We can see here that this (insane) method toString() does not even print the whole state of the value object whose precision is in milliseconds (missing! in the pattern). Another even more confusing thing is: This special formatting method uses external context information for printing, namely the system timezone of the running JVM. This zone is NOT part of the state of java.util.Date.
Conclusion: Let's treat objects of java.util.Date best as without any format (meaning ignoring the method toString()) and always use an extra formatter like SimpleDateFormat.

Java time instant formatting discrepancies

The way Java time handles simple things like timestamps leaves me a little taken aback. Maybe I'm doing it wrong.
I want to generate an ISO 8601 timestamp string. The obvious way would be to create an Instance.now() and format it use DateTimeFormatter.ISO_INSTANT to format it. Except that Instance has no format() method, so I can't format it with the "instance" formatter. Imagine that.
So I have to create a ZonedDateTime from the instance. It shouldn't matter which zone I choose, so I choose UTC because that's what DateTimeFormatter.ISO_INSTANT is going to put it in anyway:
Instant.now().atZone(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)
Now I get back a string, and obviously I want to get it back to a ZonedDateTime instance, because that's what I used to format it with! So I try:
ZonedDateTime.parse(timestamp, DateTimeFormatter.ISO_INSTANT)
It complains at me that there is no time zone information. But I used a ZonedDateTime to generate it --- it's not my fault that it wouldn't let me use an Instance to format it.
Oddly Instance doesn't have a format() method, but it does have a parse() method, which, again oddly, is parsed using DateTimeFormatter.ISO_INSTANT (even though I can't format an Instance using that formatter).
As pointed out in the comments, I can use DateTimeFormatter.ISO_INSTANT.format(Instance.now()) to format an instance directly, so why isn't there an Instance.format(…)?
So just generating and parsing a timestamp seems convoluted and inconsistent. Or am I doing it wrong?
First, you can just DateTimeFormatter.ISO_INSTANT.format(Instant.now()).
Next, I don't see why you expect to parse back what you've formatted. Formatting is not guaranteed to be a lossless operation. If you format a LocalDateTime with just the year, you wouldn't expect to parse it back to LocalDateTime, would you?
And of course you can parse Instant using DateTimeFormatter.ISO_INSTANT. DateTimeFormatter.ISO_INSTANT.parse(text, Instant::from) - this is what Instant.parse(...) does.
There is no need for a format(DateTimeFormatter) method in Instant, because toString() does the job. The toString() method of Instant is implemented as:
return DateTimeFormatter.ISO_INSTANT.format(this);
Thus, all you need to do is call instant.toString().
To round-trip parse this back in, simply use parse():
Instant instant = Instant.parse(text);
Why do you need to respecify the formatter when parsing back the string?
Can't you just do ZonedDateTime.parse(timestamp);?

Dealing with Date Object and TimeZone in Java 7

I am developing a library to store complex data in an Object. One of the field in this object is a date. When I set the date using setter method, it is assumed that the date object is in GMT timezone. Internally, the Date is stored as a long with the number of milliseconds from epoch. In my get() method, I am doing the following :
return new Date(storedDateinMilliseconds);
The problem is that if anyone is calling toString() on the returned object, it uses the default timezone to return the date. Therefore, the returned date does not always match with the date provided in GMT. Is there a way to fix this? so that the user of this implementation will always get the GMT date when they invoke toString()?
I tried the following :
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
But this would modify the default timezone of the application using it.
As Sotirios Delimanolis’ comment said, you are giving a java.util.Date object to the calling programmer. What she does with it is up to her. And it is up to her to understand all the goofy problems that come with that object including its toString method applying the JVM’s current default time zone in generating a string representation of its date-time value.
If you want to return a date-time value with an assigned time zone, then return a different object.
Alternative Date-Time Objects
You have at least three alternatives to returning a java.util.Date object.
java.time
In Java 8 and later, the obvious choice is to use the new java.time framework (Tutorial). Give the calling programmer a ZonedDateTime object which is basically a Instant object plus a ZoneId object.
Tip: When specifying a time zone, use a proper time zone name. Never use the 3-4 letter codes like EST or IST.
Joda-Time
Joda-Time was the inspiration for java.time. This 3rd-party library is excellent, and well-worn from popular use. It supports multiple versions of Java and Android too.
The DateTime class is a moment on the timeline plus a time zone, similar to java.time’s ZonedDateTime.
ISO 8601
A third alternative is to give the calling programmer a string representation of a date-time value. The obvious choice of formats is to use those defined by the ISO 8601 standard. These formats are sensible, well thought-out, and unambiguous.
2015-09-16T18:06:14Z
…or…
2015-09-16T11:06:14-07:00
Both java.time and Joda-Time use these formats by default in parsing and generating strings. The formats are wisely extended by java.time to append the proper name of the time zone in square brackets.
2015-09-16T11:06:14-07:00[America/Los_Angeles]
Never Adjust Default Time Zone
You stated that setting the default time zone affected your entire app. Wrong. It affects all code of all apps in all threads running in that JVM. Worse, it does so immediately during runtime while that other code is running.
Set the default time zone only as a last resort when all other approaches to resolve a date-time problem have been exhausted. This is rare. The usual solution is to:
Use java.time or Joda-Time.
Always specify the desired/expected time zone rather than rely implicitly on the default.
Use UTC in most of your business logic, data storage, and data exchange.
Avoid whenever possible the mess that is java.util.Date/.Calendar.
Search StackOverflow
All of these topics have been discussed many times over on StackOverflow.com. Please search for more information and examples.
AFAIK, you have 2 options:
Option 1. This may sound like an overkill, but you could roll out your own Date object just for this complex class of yours, and overwrite the toString() method. Maybe something like
public class GMTDate extends java.util.Date {
#Override
public String toString() {
//return GMTDate
}
}
Option 2: Keep your date as java.util.Date, but don't expose a public getter for it. Expose instead a public getter that returns your date in GMT format, and maybe a public getter that returns your date as a long (with the number of milliseconds from epoch)
EDIT:
And a 3rd option: AspectJ. You can use aspect oriented programming to intercept calls to the toString() method and return a GMT string date
Relevant Stack Overflow Question: AspectJ: Intercept method execution/call and make it return

XmlBeans XmlDateTime format without timezone info

I'm getting an Xml representation of an XmlObject using the xmlText() method. The XmlDateTime objects are coming out with timezone offsets at the end of the string which is valid according to XML Schema: dateTime. Is there any way to force the XmlObject to convert to xml with the Zulu formatting?
Getting this: 2002-10-10T12:00:00-05:00
and need this instead: 2002-10-10T17:00:00Z
I was asking about the instantiation of the XmlDateTime object because I ran into a similar issue a while ago. From what I could figure out, the way the XmlDateTime is printed to xml depends on the value of the internal representation, which in turn depended on the setter which was invoke to provide that value. The issue was with the setDate(...) method.
The default implementation of XmlDateTime keeps the value of the datetime internally as an org.apache.xmlbeans.GDate which is built using a GDateBuilder. When you set the date on the XmlDateTime object it eventually passes the value onto a GDateBuilder.
If you look at the source of the setDate() method, the javadoc states that:
Sets the current time and date based on a java.util.Date instance.
The timezone offset used is based on the default TimeZone. (The default TimeZone is consulted to incorporate daylight savings offsets if applicable for the current date as well as the base timezone offset.)
If you wish to normalize the timezone, e.g., to UTC, follow this with a call to normalizeToTimeZone.
Since the XmlDateTime object has a setGDate(...) method you can test the normalize method like this:
XmlDateTime xmlDateTime = XmlDateTime.Factory.newInstance();
xmlDateTime.setStringValue("2002-10-10T12:00:00-05:00");
System.out.println(xmlDateTime.xmlText());
GDateBuilder gdb = new GDateBuilder(xmlDateTime.getDateValue());
gdb.normalize();
xmlDateTime.setGDateValue(gdb.toGDate());
System.out.println(xmlDateTime.xmlText());
For me this printed:
<xml-fragment>2002-10-10T12:00:00-05:00</xml-fragment>
<xml-fragment>2002-10-10T17:00:00Z</xml-fragment>
That was the only way that I could get it to print in UTC.
I hope there is a better way, although sadly I couldn't find it...

Parsing xs:date with timezone into Joda LocalDate

When parsing dates and times from XML documents into JodaTime objects, I use a common set of conversion utilities, generally using the parsers and formatters supplied by org.joda.time.format.ISODateTimeFormat.
This works fine in the majority of cases, but this time I'm seeing documents with the xs:date value of the format 2010-08-19Z. This is a perfectly valid xs:date value, but none of the standard ISODateTimeFormat-generated LocalDate parsers I've tried will accept it. The closest I can find is ISODateTimeFormat.dateParser(), which will accept the rather odd-looking 2010-08-19TZ, but not 2010-08-19Z (note the T).
This is all quite irritating, since both Joda and XML Schema are supposed to strictly adhere to the ISO date/time formatting rules, but either one of them isn't, or the spec is fuzzy.
Before I admit defeat and hand-roll a custom format, can anyone point me at a ISODateTimeFormat-sourced parser that will read that value?
I believe that according to ISO-8601, 'Z' is part of the time value. The 'T' separator is used only to create combined date/time values. A strict reading of this implies that 'Z' cannot appear after a date without a time value, which can be empty, thus the "odd-looking" 2010-08-18TZ.
This appears to be a slight impedance mismatch between the definitions of xs:date and ISO-8601.
EDIT: I found a copy of ISO 8601. It does not define the concept of a "time-zoned date" such as is defined in the XML Schema Datatypes spec.
Rather than writing one from scratch, how about a simple wrapper that converts xs:date instances with timezones into corresponding ISO-8601 values (i.e. just insert the 'T') and then use the existing ISODateTimeFormat.dateParser()?

Categories