22

I have a Date object which represents a UTC time. When I use the method getTime() to get the long value of this object, the value returned corresponds to our local time (central US). What is the correct way to get the value back which corresponds to the original UTC time?

Thanks

jwchang
  • 10,584
  • 15
  • 58
  • 89
flyingfromchina
  • 9,571
  • 12
  • 35
  • 38

6 Answers6

26

tl;dr

Instant.now()

…and…

Instant.ofEpochMilli( n ) 

…and…

instant.toEpochMilli()

Date is always in UTC

When I use the method getTime() to get the long value of this object, the value returned corresponds to our local time (central US).

No, the value returned from Date::getTime() always corresponds to UTC (virtually the same thing as GMT in this context). To quote the class doc:

Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object.

So your Question is nonsensical in that a Date is already in UTC. No need to “get the value back which corresponds to the original UTC time”,

You may be confusing the behavior of getTime with that of the toString method. The toString method annoyingly and confusingly applies the current default time zone in the process of generating the String. So the string output appears with a time zone while in fact there is no time zone to be set or gotten from the Date itself. (There actually is a zone deep within the Date but that is irrelevant to this discussion here. This class is a confusing mess!)

java.time

The modern way to do this is using java.time classes.

Table of date-time types in Java, both modern and legacy

Instant

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Get the current moment.

Instant instant = Instant.now();

You can convert a Date to its modern replacement by calling one of the new conversion methods added to the old date-time classes. Just call toInstant, quite easy.

Instant instant = myJavaUtilDate.toInstant();  

I do not recommend at all using a count-from-epoch number as a way of tracking time. Stick with the java.time objects instead. When outside Java, serialize to text use the ISO 8601 formats.

But if you must, you can extract a count of milliseconds since epoch of 1970-01-01T00:00:00Z. Note that this may involve data loss! An Instant has a finer resolution of nanoseconds. So going to milliseconds may lop off a fraction of the fraction of a second.

long millisecondsSinceEpoch = instant.toEpochMilli();  // Caution: Possible data-loss in going from nanoseconds to milliseconds.

Going the other direction, from a count to an Instant.

Instant instant = Instant.ofEpochMilli( millisecondsSinceEpoch ) ;

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

  • Java SE 8 and SE 9 and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • So if I create a file at the same "time" in Paris and in Manila, their [`lastModified()`](https://docs.oracle.com/javase/8/docs/api/java/io/File.html#lastModified--) will be the same? – Matthieu Jan 09 '18 at 16:08
  • 2
    @Matthieu Yes, a person in Paris and a person in Manila *simultaneously* creating a folder at the same moment while talking to each other on the phone will both see the same `long` number returned by this command (assuming their computer clocks are set accurately, and assuming each action is perfectly synchronized). That command is documented as returning a count of milliseconds since the epoch reference date of first moment of 1970 **in UTC**, the same epoch as java.time. Use the `Instant.ofEpochMilli( millisecondsSinceEpoch )` code seen above in this Answer. – Basil Bourque Jan 09 '18 at 16:20
25

The DateFormat class has a method for setting your preferred time zone, and there's a time zone class that has a setting for UTC time.

So, for example,

SimpleDateFormat sdf = new SimpleDateFormat();
sdf.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
Date yourUtcDate = sdf.parse(yourOriginalDate);
Pops
  • 30,199
  • 37
  • 136
  • 151
24

java.util.Date has no concept of timezone. It simply holds time relative to epoch, which is Jan 1 1970 00:00:00 UTC. Date is a model, separate from the view. When you display the date, the concept of timezone then is applied. Date's toString() displays a human readable date in the default timezone. You can either use a DateFormat to display a Date in a different timezone (such as UTC), or change the JVM's default timezone.

Steve Kuo
  • 61,876
  • 75
  • 195
  • 257
  • 1
    Update: The troublesome `java.util.Date` class is now legacy, supplanted by `java.time.Instant`. Both represent a point on the timeline in UTC, with a finer resolution of nanoseconds in `Instant`. – Basil Bourque Jan 13 '18 at 04:28
8

getTime() returns "the number of milliseconds since January 1, 1970, 00:00:00 GMT", nothing more, nothing less (obviously, you have to create it correctly). You can format it however you want, starting with e.g. the GregorianCalendar(TimeZone) constructor.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
1

Most of the Date class functions are deprecated as they are now shifted in Calendar class.

Here is code to get UTC time from Calendar.

Date date = new Date(timeStamp);
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
calendar.setTime(date);

Here is the sample code to get the year, month, etc.

System.out.println(calendar.get(Calendar.YEAR));
System.out.println(calendar.get(Calendar.MONTH));

Calendar also has support for many other useful information like, TIME, DAY_OF_MONTH, etc. Here the documentation listing all of them Please note that the month are 0 based. January is 0th month.

Amol Dixit
  • 611
  • 7
  • 13
  • 1
    Actually, `Calendar` class itself has been legacy for years now, supplanted by the *java.time* classes defined in JSR 310. Suggesting its use in 2018 is poor advice. The old legacy date-time classes are troublesome, confusing, poorly-designed, and flawed. – Basil Bourque Feb 21 '18 at 08:24
-1
    LocalDateTime now = LocalDateTime.now(Clock.systemUTC());
    Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
    Date formattedDate = Date.from(instant);

    return formattedDate;
  • 1
    ??? Why not just `Instant.now()` and be done with it? Just as I covered in [my year-old Answer](https://stackoverflow.com/a/41293971/642706). – Basil Bourque Jan 13 '18 at 04:22
  • This answer is wrong. The code is doing a time zone conversion, which results (in most time zones) in an incorrect result. – Ole V.V. Oct 27 '19 at 14:04