开发者

"Java Date() returns date in UTC" - what does it actually mean?

My question might be trivial but I'm just looking for clarifications. I read somewhere in SO that Java's Date() is actually always in UTC time, how come when I create a Date() object and print it using toString(), 开发者_运维知识库it displays the local time. If this is not the right way to print it, what should it be so I would get the UTC time?


For formatting, you should really use a DateFormat implementation (e.g. SimpleDateFormat). That will let you specify the time zone (and output format). Date itself has no concept of time zones - it represents an instant in time, using the "milliseconds since the Unix epoch" as storage. The toString() method just converts whatever instant is represented into a local time using the system default time zone.

Personally I'd advise moving away from the built-in date/time API entirely and using Joda Time as a far more sensible library.


“Java Date() returns date in UTC” - what does it actually mean?

UTC is the baseline against which we adjust the time-of-day around the globe.

Since the caveman days, noon, or 12:00, is when the sun is directly overhead. Of course, that means different moments in different places. Noon in Japan happens hours earlier than in Europe, and noon arrives even later in the Americas.

In the modern era, humans created time zones where noon would apply to a wide swath of land, so wide that the sun may not be overhead simultaneously across all of it. So the sun, or “solar time”, could no longer be used to define time. The modern time zone is defined as being a certain number of hours-minutes-seconds from the baseline.

What baseline? That baseline was arbitrarily chosen by the fate of history to be the latitude that runs through the Royal Observatory, Greenwich in London, England, UK. Time zones to the east are a certain number of hours-minutes-seconds ahead of UTC, and to the west a certain number behind UTC. For example, India is five and half hours ahead of UTC, and Martinique in the Caribbean is four hours behind UTC.

If the offset is zero hours-minutes-seconds, then we say we are “at UTC” or “in UTC”.

Java's Date() is actually always in UTC time

Yes, the java.util.Date class, despite its unfortunate name, represents a date with time-of-day with an offset-from-UTC of zero.

The Date class is now obsolete, by the way. The java.time.Instant class is now used as its replacement to represent a moment in UTC. Instant has a resolution of nanoseconds, finer than the milliseconds of Date.

when I create a Date() object and print it using toString(), it displays the local time

There are many problems with the legacy date-time classes. One is the poor naming, as mentioned above. Another is the well-intentioned by unfortunate design decision made that Date::toString should dynamically apply the JVM’s current default time zone to adjust from UTC while generating the text. This bad decision has caused no end of confusion and pain to Java programmers, as it creates the illusion that java.util.Date has a time zone assigned.

As an aside… Even worse, the java.util.Date does have a time zone, but buried deep in its source code with no accessor getter/setter methods. But that zone does affect some behavior such as determining equality between objects of this class. Confusing? Yes. As I said, these legacy date-time classes are riddled with poor design decisions.

If this is not the right way to print it, what should it be so I would get the UTC time?

The right way is to avoid the Date class entirely. Use only the java.time classes instead.

➥ To get the current moment in UTC, use Instant.now.

Instant instant = Instant.now() ;

Tip: If you want to alter the time for the purpose of artificial testing, pass an alternate Clock to Instant.now( Clock ).

To generate a String with text representing the value of that Instant in standard ISO 8601 format, simply call toString. Fortunately this class does not inject a time zone like Date does. The Instant::toString method tells the simple truth, text of the moment in UTC.

String output = instant.toString() ;

2019-12-03T10:15:30.032163Z

Be clear that date-time objects such as Instant do not have a “format”. Only text representing the value of those objects have a format. The text and the date-time object are distinct and separate from each other. A date-time object can generate such text, and can parse such text, but is not actually the text.

If you need flexibility in generating text in other formats, apply a ZoneOffset to get a OffsetDateTime object, or apply a ZoneId to get a a ZonedDateTime object. Apply a DateTimeFormatter object to generate the text.


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.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

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.


A java.util.Date object simply represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone e.g.

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) {
        Date date = new Date();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);

        sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
        String strDateNewYork = sdf.format(date);
        System.out.println(strDateNewYork);

        sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        String strDateUtc = sdf.format(date);
        System.out.println(strDateUtc);
    }
}

Output:

2021-06-20T09:43:39.517-04:00
2021-06-20T13:43:39.517Z

ONLINE DEMO

java.time

The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.

Also, quoted below is a notice from the home page of Joda-Time:

Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.

Solution using java.time, the modern Date-Time API:

import java.time.Instant;

public class Main {
    public static void main(String[] args) {
        Instant now = Instant.now();
        System.out.println(now);
    }
}

Output:

2021-06-20T13:37:42.174352Z

ONLINE DEMO

An Instant represents an instantaneous point on the timeline in UTC. The Z in the output is the timezone designator for a zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).

Learn more about the modern Date-Time API from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜