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.
Related
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...
I feel like this question has been asked in one way or another, but I'm still not confident of my result.
I have an xsd:duration which will give me a desired expiration described in years, months, days, and seconds. I can collect the integer values of these parts with, for example, duration.getYears() or duration.getMonths().
Because my chosen db is Cassandra, I want to exploit the TTL option, which will automatically expire an inserted row after a specified number of seconds.
The critical part is getting from xsd:duration to an integer/long value of seconds which respects the Gregorian calendar (where 1 month from now is not simply 30.41 days, but 31).
At the moment, I'm using the following code:
LocalDateTime then = LocalDateTime.now().plusYears(duration.getYears()).plusMonths(duration.getMonths()).plusDays(duration.getDays()).plusHours(duration.getHours()).plusMinutes(duration.getMinutes()).plusSeconds(duration.getSeconds());
long ttlMillis = then.toInstant(ZoneOffset.UTC).toEpochMilli() - Instant.now().toEpochMilli();
Is there a quicker/cleaner way to do this?
I'm also not sure if I should worry about large durations... My particular use cases wouldn't call for anything larger that 2 years.
Informational note for all:
You are talking about javax.xml.datatype.Duration, not java.time.Duration.
Your questions:
a) Is there a quicker way to do this (using Java-8)? Hardly. The designers of JSR-310-team responsible for the new date- and time library in Java-8 have not cared much about the bridge to the existing XML-classes in JDK. So there is no direct way to convert from xml-duration to any kind of JSR-310-duration.
Keep also in mind that the JSR-310-classes Period (with state consisting of years, months and days) and Duration (with state consisting of seconds and nanoseconds) are not really designed for representing an xml-duration (which has more units as seen in your code). So I doubt if we might see a well-defined bridge between JSR-310 and XML in the future (maybe only on millisecond base?). The sign handling is also completely different in JSR-310 and XML. So be cautious if you have negative sign in xml-duration.
b) Is there a cleaner way to do this (using Java-8)? Yes, a little bit. One thing to consider is: I would use the clock as time source for the actual instant only once and not twice as you have done it. Example for this (very) minor improvement:
Instant now = Instant.now();
LocalDateTime start = now.atOffset(ZoneOffset.UTC).toLocalDateTime();
LocalDateTime end =
start.plusYears(duration.getYears())
.plusMonths(duration.getMonths())
.plusDays(duration.getDays())
.plusHours(duration.getHours())
.plusMinutes(duration.getMinutes())
.plusSeconds(duration.getSeconds());
long deltaInMillis = end.toInstant(ZoneOffset.UTC).toEpochMilli() - now.toEpochMilli();
Second thing to consider: The xml-duration class is designed for interoperation with java.util.Date. So you also have this short alternative:
Date start = new Date();
long deltaInMillis = duration.getTimeInMillis(start);
This alternative is not only much shorter, but is probably also more precise because it takes into account the millisecond part. According to the documentation you should only worry about the correctness if you have duration items in long range (excessing the range of int). Another topic is the relationship to any hidden timezone calculation. I have not seen any hint in the documentation, so this is maybe the only item which can make you worry (either local timezone? or UTC? - not tested).
c) Why worry about large durations? Even if your duration is larger than let's say some centuries possibly crossing the validity limits of historic gregorian calendar, you should keep in mind that xml-duration only uses the proleptic gregorian calendar, not the historical one. And LocalDateTime uses the same proleptic gregorian calendar, too. If such a large duration is related to any real data is another good question however.
After doing my research I wasn't able to find a method or data type that should be used for variable in order to store time in format of HH:MM, I did find methods to get this from a string like "14:15:10", but I think this is not the best way, as I'll need to add or subtract from time. I tried doing this as a double, but ran into following issue, when you have a time like 05.45 stored and add 0.15 (or 15 minutes) to it, the result is 05.60 where as with HH:MM format you'd expect it to be 06.00.
I'm looked through java documentation and still am, but can't seem to find any way to achieve this, closest I got to is date format like dd/mm/yyyy hh:mm:ss
Use Joda Time. It provides much better operations to do date/time manipulation than standard java dates. If you want to use internal JDK classes, use java.util.Date.
Since Java 8, you can use the new API for dates and times, including Instant, ZonedDateTime and LocalDateTime. This removes the use for the third party library Joda time. It also makes calculations more easy and correct. The advice below is a bit dated but still has some good points.
—————
What you definitely should NOT do is store them in your own custom format. Store the Long value that represents the Unix Epoch.
A DateTime is nothing more than a number to a computer. This number represents the amount of seconds (or milliseconds) since 1970-01-01 00:00:00 UTC. It's beyond the scope of this answer to explain why this date was universally chosen but you can find this by searching for Unix Epoch or reading http://en.wikipedia.org/wiki/Unix_time.
This also means there is NO timezone information stored in a DateTime itself. It is important to keep this in mind when reasoning about dates and times. For things such as comparing DateTime objects, nothing concerning localization or timezones is done. Only when formatting time, which means as much as making it readable to humans, or for operations such as getting the beginning of the day, timezones come into play.
This is also why you shouldn't store the time like 20:11:15 in a string-like format because this information is meaningless without timezone information. I will give you 1 example here: Consider the moment when the clock is moved back 1 hour, such as when moving away from daylight savings time. It just happened in a lot of countries. What does your string 02:30 represent? The first or the second one?
Calculations such as subtraction are as easy as doing the same with numbers. For example: Date newDate = new Date(date1.getTime() - date2.getTime());. Or want to add an hour to a date? Date newDate = new Date(oldDate.getTime() + 1000 * 60 * 60);
If you need more complex stuff then using Joda time would be a good idea, as was already suggested. But it's perfectly possible to just do even that with the native libraries too.
If there's one resource that taught me a lot about date/time, it would be http://www.odi.ch/prog/design/datetime.php
Java has java.sql.Time format to work with time-of-day values. Just import it and create variables.
import java.sql.Time;
//now we can make time variables
Time myTime;
Just saw it on https://db.apache.org/derby/docs/10.4/ref/rrefsqlj21908.html
The answer that is right for your case depends on what you want to do.
Are you using a RDBMS as your persistence engine?
If so, are you already working with legacy data formats or are you building a database from the ground up?
Are you simply storing this data, or will you be doing extensive date arithmetic and/or precedence calculations?
Are you in one time zone or do you need to work with time instants across many time zones?
All of these things are important and factor into your decision of how to represent your times and dates.
If your needs require a lot of date arithmetic (eg. determining days between dates) or sorting based on timestamps, then consider using a floating point date format. The advantage of using a numeric format for timestamps is that doing date arithmetic and comparison/sorting operations becomes trivial; you merely do simple arithmetic. Another advantage is that floats and longs are primitive data types. They do not need to be serialized, they are already extremely lightweight, and everything you need to use them requires no external dependencies.
The main disadvantage to using numeric formats for timestamps is that they are not human friendly. You'll need to convert them to and from a String format to allow users to interact. Oftentimes, this is worth the effort. See: How do I use Julian Day Numbers with the Java Calendar API?
I recommend that you consider storing timestamps as Julian Day Numbers (JDNs) or Modified Julian Day Numbers (MJDs). Both will represent dates and times to millisecond precision using an 8 byte float. Algorithms for converting to and from display formats for both of these are highly standardized. They confer all the advantages of using numeric dates. Moreover, they are defined only for GMT/UTC which means that your timestamps are already universalizable across time zones right out of the box (as long as you localize properly).
If you dont want the full date object, your best bet is to store it in a string, but I personally would still recommend date as it also contains a lot of convenient methods that will come in handy. You can just get the time as a whole from a date object and ignore the rest.
In terms of "storing" a date, you should use a long. This is how the system sees it and how all calculations are performed. Yes, as some point out you will eventually need to create a String so a human can read it, but where people run into trouble is when they start thinking of a date in terms of format. Format is for readability, not for calculations. java.util.Date and java.util.Calendar are fraught with issues (Effective Java, Bloch, et. al. has plenty to say about it) but are still the norm if you need handy date operations.
I have 2 different computers, each with different TimeZone.
In one computer im printing System.currentTimeMillis(), and then prints the following command in both computers:
System.out.println(new Date(123456)); --> 123456 stands for the number came in the currentTimeMillis in computer #1.
The second print (though typed hardcoded) result in different prints, in both computers.
why is that?
How about some pedantic detail.
java.util.Date is timezone-independent. Says so right in the javadoc.
You want something with respect to a particular timezone? That's java.util.Calendar.
The tricky part? When you print this stuff (with java.text.DateFormat or a subclass), that involves a Calendar (which involves a timezone). See DateFormat.setTimeZone().
It sure looks (haven't checked the implementation) like java.util.Date.toString() goes through a DateFormat. So even our (mostly) timezone-independent class gets messed up w/ timezones.
Want to get that timezone stuff out of our pure zoneless Date objects? There's Date.toGMTString(). Or you can create your own SimpleDateFormatter and use setTimeZone() to control which zone is used yourself.
why is that?
Because something like "Oct 4th 2009, 14:20" is meaningless without knowing the timezone it refers to - which you can most likely see right now, because that's my time as I write this, and it probably differs by several hours from your time even though it's the same moment in time.
Computer timestamps are usually measured in UTC (basically the timezone of Greenwich, England), and the time zone has to be taken into account when formatting them into something human readable.
Because that milliseconds number is the number of milliseconds past 1/1/1970 UTC. If you then translate to a different timezone, the rendered time will be different.
e.g. 123456 may correspond to midday at Greenwich (UTC). But that will be a different time in New York.
To confirm this, use SimpleDateFormat with a time zone output, and/or change the timezone on the second computer to match the first.
javadoc explains this well,
System.currentTimeMillis()
Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the underlying operating system and may be larger. For example, many operating systems measure time in units of tens of milliseconds.
See https://docs.oracle.com/javase/7/docs/api/java/util/Date.html#toString().
Yes, it's using timezones. It should also print them out (the three characters before the year).
The documentation for Date.getTimezoneOffset says:
Deprecated. As of JDK version 1.1, replaced by
-(Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000).
Why was it deprecated? Is there a shorter way (Apache Commons?) to get the offset from UTC in hours/minutes? I have a Date object ... should I convert it to JodaDate for this?
And before you ask why I want the UTC offset - it's just to log it, nothing more.
There are 2 questions here.
Why was Date.getTimezoneOffset deprecated?
I think it is because they actually deprecated nearly all methods of Date and moved their logic to calendar. We are expected to use generic set and get with the parameter that says which specific field we need. This approach has some advantages: less number of methods and the ability to run setters in a loop passing a different field each time. I personally used this technique a lot: it makes code shorter and easier to maintain.
Shortcut? But what's wrong with call
Calendar.get(Calendar.DST_OFFSET) comparing to
Calendar.getTimeZoneOffset()
As far as I can see the difference is 6 characters.
Joda is a very strong library and if you really have to write a lot of sophisticated date manipulation code switch to it. I personally use the standard java.util.Calendar and don't see any reason to use external libraries: good old calendar is good enough for me.
All of the date manipulation logic was moved out of Date once the Java implementers realized that it might need to be implemented differently for different types of calendars (hence the need to use a GregorianCalendar to retrieve this info now). A Date is now just a wrapper around a UTC time value.
Take care before you paste code from this page.
Perhaps just me but I believe that in order to get the tz offset in minutes you need to do
int tzOffsetMin = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET))/(1000*60);
rather than what the Javadoc says, which is:
int tzOffsetMin = -(cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET))/(1000*60);
Calendar.ZONE_OFFSET gives you the standard offset (in msecs) from UTC. This doesn't change with DST. For example for US East Coast timezone this field will always be -6 hours regardless of DST.
Calendar.DST_OFFSET gives you the current DST offset (in msecs) - if any. For example during summer in a country that uses DST this field is likely to have the value +1 hour (1000*60*60 msecs).