Timespan/Edm.Time format in OData - odata

What is the correct format to be used for Edm.Time ?
I see in the protocol document the format for DateTime and DateTimeOffset as follows:
Datetime : "yyyy-MM-dd'T'HH:mm:ss.fff"
DateTimeoffset : "yyyy-MM-dd'T'HH:mm:ss.fffZ"
I did check the protocol here : http://www.w3.org/TR/xmlschema-2/ but could not get the formatting to be used for Edm.Time.
Currently we are using XmlConvert.ToString to convert the time span value to a string representation.
Is there any specific representation that OData recommends for Timespan ?

The formats should be reasonably well documented here, which points you to this link (in the case of Edm.Time).
From XML Schema 2:
3.2.8.1 Lexical representation
The lexical representation for time is the left truncated lexical
representation for dateTime: hh:mm:ss.sss with optional following time
zone indicator. For example, to indicate 1:20 pm for Eastern Standard
Time which is 5 hours behind Coordinated Universal Time (UTC), one
would write: 13:20:00-05:00. See also ISO 8601 Date and Time Formats
(§D).
Note that time-and-date-land have had their issues over the years. The date format varies based upon payload format and version. For instance, JSON Verbose used the /Date(...)/ format for OData v2, but changed to ISO 8601 in OData v3 (much to the collective relief of anyone who doesn't have to implement an OData server and care about all these nuances). This is similar to the struggles that the ASP.NET stack has gone through: http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx.

Related

How can I parse a particular representation of ISO 8601 timestamp (one without any whitespaces) using DateTimeFormatter?

I am trying to parse an ISO 8601 timestamp which looks like this: "20220603T054813Z". My supervisor gave me this timestamp asking me to parse it (she found it on wiki under the ISO-8601 page) but I couldnt find information regarding this type of timestamp anywhere else.
I am trying to parse it using a LocalDateTime instance and using a pre-defined format but I cant find any. Using any of the classes doesnt work neither do the pre-defined formatters for ISO 8601 timestamps. There's no example in the documentation that explains how to handle this particular case and that makes me wonder if this is a valid ISO 8601 case. It does work with my own created format but I am writing a logic to handle ISO 8601 cases without me having to define a custom format, as much as possible. atleast for the ISO 8601 timestamps. Is this a valid ISO 8601 timestamp even? Because usually they have separators for date and time.
Is there a way to handle timestamps like these, which doesnt have any separators or whitespaces, with a pre-defined formatter? Maybe i am missing something. Any help would be appreciated, thanks!

Joda DateTimeFormatter.parseDateTime is failing for General time zone('z')

Confused with the use of General time zone('z'). Joda is failing in below sample code. Can somebody help me to understand why the behavior is like this? How can I parse a date in differnt timezone using this format in Joda?
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
System.out.println(sdf.parse("2019.09.17 AD at 15:29:00 IST"));
DateTimeFormatter pattern = DateTimeFormat.forPattern("yyyy.MM.dd G 'at' HH:mm:ss z");
DateTime dateCtxParamDateTimeObj = pattern.parseDateTime("2019.09.17 AD at 15:29:00 IST");
System.out.println(dateCtxParamDateTimeObj.toDate());
}
Output
Tue Sep 17 15:29:00 IST 2019
Exception in thread "main" java.lang.IllegalArgumentException: Invalid format: "2019.09.17 AD at 15:29:00 IST" is malformed at "IST"
at org.joda.time.format.DateTimeFormatter.parseDateTime(DateTimeFormatter.java:945)
Edit: You need to tell Joda-Time what you mean by IST
Thanks go to HarryQ, who pointed me here to where this is documented.
DateTimeUtils.setDefaultTimeZoneNames(Collections.singletonMap(
"IST", DateTimeZone.forID("Europe/Dublin")));
DateTimeFormatter pattern = DateTimeFormat.forPattern("yyyy.MM.dd G 'at' HH:mm:ss z");
DateTime dateCtxParamDateTimeObj = pattern.parseDateTime("2019.09.17 AD at 15:29:00 IST");
System.out.println(dateCtxParamDateTimeObj);
The output from this snippet is:
2019-09-17T15:29:00.000+01:00
Lowercase z in a format pattern string works differently when formatting and when parsing in Joda-Time. Joda-Time can format time zone names for all available time zones, but with default settings it can only parse a few back. Which it can parse is controlled by the default time zone names of the DateTimeUtils class. It comes with a map of 10 time zone abbreviations as documented in the DateTimeUtils.getDefaultTimeZoneNames method (link at the bottom): CST, MDT, GMT, PST, PDT, UTC, EDT, CDT, EST and MST. We can substitute with a different map. What I am doing above is substituting with a map of just one abbreviation for the illustration. This risks breaking other code, so a better approach for most purposes would be to build a map containing both the abbreviations that were there before and that or those that we want to be able to parse too.
The map I provided above assumes that IST is for Irish Summer Time (and on September 17, 2019, Ireland was using summer time (DST)). You hardly meant Israel Standard Time because Israel too used summer time, IDT. A third likely understanding is India Standard Time:
DateTimeUtils.setDefaultTimeZoneNames(Collections.singletonMap(
"IST", DateTimeZone.forID("Asia/Kolkata")));
2019-09-17T15:29:00.000+05:30
You notice that we now get offset +05:30 instead of +01:00, so a different point in time. The ambiguity may also be the reason why Joda-Time refuses to make its own assumption about what you intended and therefore needs us to tell it before it can parse the string.
Original answer
It’s a documented limitation in Joda-Time. From the documentation of DateTimeFormat:
Zone names: Time zone names ('z') cannot be parsed.
Also note that IST and many other time zone abbreviations are ambiguous, so if there is any way you can avoid parsing one, by all means do avoid it. IST may be for Irish Summer Time, Israel Standard Time or India Standard Time, and there’s no guarantee which of them you get, or if you may even get Iceland Standard Time.
If you insist, one possible solution is to follow the advice from the Joda-Time homepage:
Note that Joda-Time is considered to be a largely “finished” project.
No major enhancements are planned. If using Java SE 8, please migrate
to java.time (JSR-310).
The DateTimeFormatter class of java.time (the modern Java date and time API) will attempt to parse a time zone abbreviation. Good luck.
Links
Joda-Time
Documentation of DateTimeUtils.getDefaultTimeZoneNames()
Related question: Why Joda DateTimeFormatter cannot parse timezone names ('z')
Documentation of DateTimeFormat
Joda-Time homepage
SO user HarryQ, who in comments under my answer to this duplicate question pointed me to the documentation of Joda-Time’s default time zone names.
Others
My answer here shows how to control the interpretation of IST while parsing when using java.time.

ISO8601 with Timezone and Timespan

I've read I can add timezone information on an ISO8601 date by appending for example Z or +02 or -03:00.
I've also read that I can add timespan information by appending a P and then the time, for example 4DT2H (4 days and two hours).
How can I combine the two? Timezone or timespan first?
E.g. 2018-10-18T14:20+02P1D vs 2018-10-18T14:20P1D+02
By having two values, you are basically describing when an event starts, and how long it lasts. Such values are covered in section 4.4.4.3 of the ISO 8601 specification, titled "Representations of time interval identified by start and duration".
The spec requires full compliance with the established formats for both the timestamp and the time period parts, separating them with a forward slash (/) character.
For example: 2018-10-18T14:20+02/P1D
The time zone offset (whether Z, or +02, or -03:00) belongs with the timestamp, before the slash.
That said, I know of few parsers that understand this format. It is compliant, but not every parser of ISO 8601 necessarily understands every part of the spec.

Time of Day in the JSON response model?

I am using ASP.NET Web Api 2 with Json.NET 6.0.1.
According to ISO 8601, dates should be interchanged in a certain way. I am using the IsoDateTimeConverter() in order to achieve this:
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IsoDateTimeConverter());
But how should "time of day" be returned in a JSON response model?
I cannot find anything for this in the ISO specification.
Should time perhaps be returned as a:
TimeSpan? (with expectation of the user to not use this as a duration representation)
DateTime? (with expectation of the user to drop off the date part)
A custom Time class
There is no standard structure in JSON for containing dates or times (see JSON.org). The de-facto stardard for dates-time values is using a string in ISO 8601 format, as you mentioned. But since there is no official standard it really comes down to what works best for you and consumers of your API.
Using a DateTime object is a reasonable choice because the support already exists in Json.Net and other serializers for converting these to and from ISO 8601 strings. So this would be the easiest to implement. However, users of your API would have to know to disregard the date portion, as you said. You could set the date to 0001-01-01 to emphasize its irrelevance. This isn't so different from the more common situation where you need only a date in your API and the time doesn't matter. Most people just set the time to midnight in this case and let it go. But, I would agree that this approach does seem to have a little bit of a "code smell" to it, given that part of the value is just noise.
Perhaps a cleaner idea is to format your DateTime value as ISO 8601, but then chop off the date portion before returning it. So users of the API would get a string that looks like 14:35:28.906Z. You could write a simple JsonConverter to handle this for you during serialization. This would sort of give you the best of both worlds -- a cleaner API, but you still can work with the familiar DateTime struct internally.
A custom Time class could also work here, but might be overkill, depending. If you do need to go there, you might want to look into a third-party library such as Noda Time, which has classes already built for these kinds of things, and also has pre-built converters for Json.Net.
I would definitely not choose TimeSpan for this purpose. Wrong tool for the job.

What formats can I use for an xforms:input bound to a node of type xs:date?

I am looking at the <xforms:input> formatting documentation and am curious if it is at all possible to display the date as "3 Jul 2011". This should formatting very simple given the use of Java's SimpleDateFormat with the mask [d] [MMM] [yyyy]. The <xforms:input> documentation makes it seem possible to change the canonical format but only references Regex expressions.
Or am I restricted to the masks [M], [D] and [Y]?
You can choose pretty much any format you want when displaying a date or time with <xforms:output>. However, when capturing a date or time with <xforms:input>, Orbeon Forms limits you to just a few formats, as documented.
The reason for this is somewhat technical: for inputs, Orbeon Forms needs to be able to both format the date/time in the format you specify, and to parse it. And the parsing is implemented to accept as many reasonable date or time formats entered by the user. For instance, if you choose a [M]/[D]/[Y] format (typical in the US), you can enter 12/2/2011, but also 12/2 (skipping the year), or even 2 (skipping both the year and the month), or today, as well as several other formats.
The bottom line is that because of this "smart parsing", the <xforms:input> can only support a number of predefined formats. Additional formats can be added, but this requires Orbeon Forms itself to be changed to support those additional formats.

Resources