How to transfer date parameters within JSON? Formatted as long? - java

I was looking around for something like a convention of how to transfer a date parameter via REST using JSON as body content type. I see some are using long as I was on couple of places where I wrote both client and server side code. I find this approach most convenient.
I want to avoid potential problems when it comes to date formats etc. Is it all up to arrangement between client and server side producers or something can be used as most correct approach?

Depending on your needs, you could use a Unix timestamp since epoch, that is, the number of seconds elapsed since January 1, 1970 (midnight UTC/GMT).
But if you want to use something more readable, consider the ISO 8601 standard, which is endorsed by the RFC 3339 and by the xkcd 1179:

There is a standard for internet date and times: https://www.rfc-editor.org/rfc/rfc3339
ISO 8601 is the canonical format...

Related

How to deal with timstamps with extra milliseconds in a Java Date

I have a javax.ws.rs REST API that accepts an object body that has a timestamp field mapped to a util Date with JPA, but something sending to it is sending a timestamp with extra milliseconds (maybe supposed to be nanoseconds?) and that causes the date to be in the future when I use the object within my request handler method.
for example this came in: "TimeStamp": "2020-04-24T16:26:11.9376071Z",
and it resolved to "2020-04-24T19:02:27" in the object.
If I use Postman and send the exact same message just with the TimeStamp reduced to 2 milliseconds it works as expected and the date is correct.
So, assuming I can't change what's being sent but want to be able to handle it, how can I shorten the milliseconds so the Date resolves correctly?
Such strings are parsed according to a pattern. The numbers following the 'dot' are parsed as milliseconds, and parsing dates is evidently configured in lenient mode, which means overflow is adjusted into the higher fields. If you parse 9376071 as milliseconds, that's 9376.071 seconds; that's about 2 hours and change. Add that to '16:26:11' and you get 19:02. So, that's what's going wrong here.
I don't see enough detail in the mechanism you're using to transit this string into a value of type java.util.Date - in various frameworks you can explicitly specify the pattern. However, the 'old' API (the one java.util.Date belongs to cannot parse this input - it has no option to parse that dangling batch of digits properly. Yes, really. The old API (java.text.SimpleDateFormat) cannot actually read ISO8601 - a grievous ommision which strongly suggests you really, really need to stop using this incapable old deprecated stuff. (ISO8601 does indeed allow any number of digits on the fractional part, and it allows a fractional part on the 'lowest' entry in the input, therefore, the timestamp you get, while somewhat exotic, fits the ISO8601 spec).
But, good news!
The newer API does it just fine!
import java.time.Instant;
import java.time.format.DateTimeFormatter;
class Test { public static void main(String[] args) {
Instant parsed =
DateTimeFormatter.ISO_INSTANT.parse("2020-04-24T16:26:11.9376071Z", Instant::from);
System.out.println(parsed);
}}
I'm not entirely sure how you can tell your framework to stop using the bad API, but once you've managed to tell it to stop hitting itself in the face with the old one, all will be well again.
Sidenote: j.u.Date is a really bad type to use; it does not represent a date at all, but an instant in time, and badly at that. In general I wouldn't use API that is so epically badly named! May I suggest java.time.Instant instead? Its name matches what it represents, and should be drop-in ready. Another workable option is ZonedDateTime or LocalDateTime depending on what it represents).

Create calendar from String date without knowing format

I want to create an instance of Calendar with string date coming from server. Now I don't know what format server is sending .
It can be changed for different countries. I know I can ask them to add another key for dateFormat and create Calendar from it. But still I want to know Is there any way to create Calendar Instance without knowing current string date format.
I have gone through this and this. But none fulfill my requirement
This is impossible.
If the server sends the value "1/2/2017", you have no way of knowing if this refers to January 2nd or February 1st.
If the server sends the value "מָחָר", in theory you could realize that this might be a Hebrew translation of the word "tomorrow" (at least, according to Google Translate), but even then, it is not clear whether this is to be taken relative to today or some other date.
If the server sends the value "I want to create an instance of Calendar with string date coming from server", you have no means of creating a date from that, at least using any algorithm that would make sense to people.
And so on.
The only reason a server should return a date in an arbitrary format is if the date would only ever be read by the user who provided the value in the first place and presented as plain text verbatim, without parsing. Otherwise, the server should supply the date in a standardized format, with the UI consuming that date being responsible for formatting it in a user-friendly (and, ideally, locale-aware) fashion.
You're welcome to try to brute-force the problem, iterating over a series of date formats and seeing if any result in a seemingly-valid date. This fails the 1/2/2017 scenario (as there are at least two formats that would return a seemingly-valid date), but perhaps you know enough about the server to narrow down the possible formats to reduce the odds of collisions like this.
The Joda Date & Time API has a date parser which can parse date strings in many formats. Note that some datetime strings can be ambiguous: 10-09-2003 could mean October 9 or September 10.

URL-compatible and easy to parse date-time format?

Using Play 2 I want to create a REST API, which shall include
/resource/<startDateTime>
meaning return all items of resource with a startDateTime greater than the startDateTime given in the URL.
So now I need some DateTime format, that can be passed by an URL in a human-readable format and is still easy to parse into a Java Date object inside my Play 2 controller. Any hints / best practices on that? Thanks for any hint!
Update:
Even better would be if Play would do the parsing for me. For java.util.Date in the routes configuration I am getting the error
No QueryString binder found for type java.util.Date. Try to implement an implicit QueryStringBindable for this type.
Is there anything predefined to parse a Date?
Update:
Expected input:
Could be e.g.
http://site.com/resource/20121231-141557 # 2012/12/31 14:15:57
or sth. else, easy readable - I don't care as long as it can be transfered using an URL and is easy to parse into a Date object.
There is an ISO standard for dates, number 8601.
http://en.wikipedia.org/wiki/ISO_8601
Date and time values are organized from the most to the least significant: year, month (or week), day, hour, minute, second, and fraction of second.
It seems you have two questions here:
How to format and parse dates easily? I think the best library for handling dates in java is Joda Time. It has methods for formatting and parsing dates in different formats.
How to define a route with a custom parser? For that, you need to define your own QueryStringBindable. Look at this answer about Doubles for an example.
You can check native Play2 Path binders here : https://github.com/playframework/Play20/blob/master/framework/src/play/src/main/scala/play/api/mvc/Binders.scala#L251
Currently, there is nothing to handle Date in parameters.
But you can write your own PathBinder on top of DateTime (JodaTime), with the ISO 8601 format (use ISODateTimeFormat)
I think it will be a good Pull request ;)

Is it safe to rely on milliseconds when calculating dates?

In java you can call the getTime() method on the Date object to represent a date in milliseconds since January 1, 1970 00:00:00 GMT. Is this representation universal across other programming language APIs?
For example, if I ask somebody who is using an API from a different programming language to give me current date and time represented in milliseconds, can I safely make the assumption that I would end up with the same date and time if I calculate this value on the server-side using java.
The reason I'm asking is because I'm building a public API over http where I want the client to provide me with a timestamp which I need to process server-side. My question really is whether it's safe to ask for a date representation in the form of milliseconds since January 1, 1970 00:00:00 GMT, rather than a full string representation such as yyyy-MM-dd'T'HH:mm:ss.SSS'Z
No, the millisecond time stamp is far from universal. I suggest you use a standard string format such as RFC 3339 for exchanging time between computers or language runtimes on the same computer. See also Wikipedia: System Time
You cannot in general assume that every numeric timestamps uses January 1, 1970 as the baseline. But it doesn't really matter, because you could specify your API as requiring timestamps in that form. It is a trivial matter to adjust the baseline and / or scale a numeric timestamp to the form you require.
So looking at the alternatives:
Numeric timestamps take marginally less space in messages, and are marginally easier and cheaper to convert. However, there is a risk of someone mis-implementing your specification by using the wrong scaling and/or baseline.
A standard (e.g. ISO) textual format uses (marginally) more space and is marginally harder to convert, but standard parser / unparser implementations exist. (There is still the risk that someone will use a variant that your specification doesn't allow.)
A non-standard textual format is not a good idea because of potential for mis-implementation and ambiguity in the format. (For example 3-letter timezones are ambiguous)
Textual formats are easier for a human to read; e.g. for debugging purposes.
But all in all, I don't think it matters if you use a numeric or (standards-based) textual format, provided that you clearly specify the required format, and what it means.
You can rely on that date format as Java also only gets that date from the operating system. It does not matter what programming language you use. See unix time in Wikipedia for a more detailed explanation.
Instead of a straight answer, I'll give a reference to OAuth.
According to the OAuth 1.0 specification:
Unless otherwise specified by the Service Provider, the timestamp is
expressed in the number of seconds since January 1, 1970 00:00:00
GMT.
So, if you really don't really need a millisecond granurality, do what others do.

XMLGregorianCalendar 2010-12-21T08:55:17E-7+01:00 E-7. What does E-7 mean

From a SOAP webservice, a date field is returned as the string:
2010-12-21T08:55:17E-7+01:00
which .NET has problems parsing. Jax has no problems with this. What does E-7 mean. And what can I do normalize it in a java server.
EDIT: I have a java server thats acts as a transistion from multiple servers with buggy timestamp. What can I do normalize it once it has been parsed by jax? .normalise() will give me UTC which I'm not sure I want.
In ISO 8601 time you always deal with Z = Zulu for UTC, but there are other military time zones as well (not part of the standard):
http://www.navycs.com/militarytime.html
E is for Echo and means the time zone UTC + 5.
I have no explanation for the -7 and +01:00 parts though.
Edit: Updated the post to make clear Z is the only allowed notation for ISO 8601 times.
Apologies for previous misreading. I can confirm that .NET can't parse it, like this:
using System;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
class Test
{
static void Main()
{
string x = "2010-12-21T08:55:17E-7+01:00";
DateTime dt = SoapDateTime.Parse(x);
Console.WriteLine(dt);
}
}
It looks like a bad SOAP service, to be honest. Looking at various bits of documentation around SOAP, it looks like SOAP date/time values should be xsd:dateTime values, which are formatted with ISO 8601 - and I can't see anything in the Wikipedia ISO 8601 page which would allow that. It's possible that Wikipedia is inaccurate, of course - but it's more likely that it's a bug in the SOAP service, IMO.
I suggest you look at the headers from the service to see if that gives a hint as to the underlying platform... then look for bugs reported against that platform producing invalid date/time values.

Categories

Resources