Is it possible to create a java.util.Date
object that is guaranteed to be UTC and at a specific time in the past, like an hour ago or a day ago, and is this a good idea?
I have reviewed the Stack Overflow question
get date as of 4 hours ago and its answers. But I want to avoid having to add more dependencies, like jodaTime
, and the accepted answer uses System.currentTimeMillis()
which would be the local timezone, would it not?
As discussed vividly in the comments, the recommendation is to use the java.time
package. The easy solution:
Instant fourHoursAgo = Instant.now().minus(Duration.ofHours(4));
System.out.println(fourHoursAgo);
This just printed
2018-01-31T14:57:44.667255Z
Since UTC time is now 18:58
, the output is what you asked for. The Instant
itself is offset neutral. Its toString
delivers time in UTC, but there was no mention of UTC in producing the Instant
, so whether it gives you what you want, I am not sure. I will give you a result that is explicitly in UTC later.
But first, if you do need a java.util.Date
, typically for a legacy API that you cannot change, the conversion is easy:
Date oldfashionedDate = Date.from(fourHoursAgo);
System.out.println(oldfashionedDate);
On my computer in Europe/Copenhagen
time zone this printed:
Wed Jan 31 15:57:44 CET 2018
Again, this agrees with the time four hours before running the snippet. And again, a Date
doesn’t have a UTC offset in it. Only its toString
method grabs my JVM’s time zone setting and uses it for generating the string, this does not affect the Date
. See the Stack Overflow question, How to set time zone of a java.util.Date?, and its answers.
As promised, if you do need to represent not only the time but also the offset, use an OffsetDateTime
:
OffsetDateTime fourHoursAgoInUtc = OffsetDateTime.now(ZoneOffset.UTC).minusHours(4);
System.out.println(fourHoursAgoInUtc);
This printed
2018-01-31T14:57:44.724147Z
Z
at the end means offset zero from UTC or “Zulu time zone” (which isn’t a true time zone). The conversion to a Date
is not much more complicated than before, but again, you will lose the offset information in the conversion:
Date oldfashionedDate = Date.from(fourHoursAgoInUtc.toInstant());
System.out.println(oldfashionedDate);
This printed:
Wed Jan 31 15:57:44 CET 2018
Link: Oracle tutorial explaining how to use java.time
You can achieve this using the java.time
package, as follows:
LocalDateTime localDateTime = LocalDateTime.now(ZoneOffset.UTC).minusHours(4);
Date date = Date.from(localDateTime.atZone(ZoneOffset.UTC).toInstant());
Gives the following output:
2018-01-31T14:58:28.908
Wed Jan 31 20:28:28 IST 2018 //20:28:28 IST is 14:58:28 UTC
Which is correctly 4+5:30
hours behind my current time - Asia/Kolkata ZoneId
.