Sandeep
Sandeep

Reputation: 1401

Getting the UTC timestamp

An old Stack Overflow posting suggests that the way to get the UTC timestamp in Java is the following:

Instant.now()   // Capture the current moment in UTC.

Unfortunately, this does not work for me. I have a very simple program (reproduced below) which demonstrates different behaviour.

On Windows: the time is the local time and it is labelled with the offset with GMT

On Linux: the time is again the local time, and it is labelled correctly for the local timezone


Question: How do we display the UTC timestamp in a Java program?


My sample source code is as follows:

import java.time.Instant;
import java.util.Date;

public class UTCTimeDisplayer {
    public static void main(String[] args) {
        System.out.println(System.getProperty("os.name"));
        Date currentUtcTime = Date.from(Instant.now());
        System.out.println("Current UTC time is " + currentUtcTime);
    }
}  

Windows Output:

C:\tmp>java UTCTimeDisplayer
Windows 10
Current UTC time is Fri Jan 22 14:28:59 GMT-06:00 2021

Linux Output:

/tmp> java UTCTimeDisplayer
Linux
Current UTC time is Fri Jan 22 14:31:10 MST 2021

Upvotes: 10

Views: 25881

Answers (7)

Dupinder Singh
Dupinder Singh

Reputation: 7789

A simple method that could work!

My requirement was date time with milliseconds

2021-11-25 19:55:00.743

private String getUTCTimestamp() {
        ZonedDateTime utc = ZonedDateTime.now(ZoneOffset.UTC);
        return utc.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));
    }

Upvotes: 3

Chris
Chris

Reputation: 1804

Instant.now() is essentially the period of time since the epoch, (midnight 1 January 1970 in UTC), but you are using a Date to present that instant. Date is a reflection of the instant with millisecond precision, but as explained in the documentation at https://docs.oracle.com/javase/8/docs/api/java/util/Date.html, presenting a date should be done using a Calendar, as the presentation of a Date depends on the host. Essentially Date wraps the instant but is displayed according to other factors.

The simplest approach now if you want to output the instant is to use OffsetDateTime so that you can elect to present the instant in your desired timezone - UTC in your case. Use either OffsetDateTime.now() or OffsetDateTime.ofInstant() but if you are using the instant within your application logic then just stick with Instant.

Upvotes: 1

Lorinczy Zsigmond
Lorinczy Zsigmond

Reputation: 1910

Sometimes your program has to work with older java versions, so here is an example for 1.5:

    java.text.SimpleDateFormat tfGMT = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    java.util.Calendar cUTC = java.util.Calendar.getInstance (java.util.TimeZone.getTimeZone ("GMT+0"));
    tfGMT.setCalendar (cUTC);
    java.util.Date d= new java.util.Date ();
    String s= tfGMT.format (d);
    System.out.printf ("now=%s [unix ts=%d.%03d]\n", s, d.getTime()/1000, d.getTime()%1000);

Mind you, the first three lines don't have to be repeat at every call, but keep in mind that SimpleDateFormat is not thread-safe. (Simple solution: create one for each thread.)

Example usage (it shows that setting TZ doesn't affect UTC-timestamp):

$ TZ=GMT+3 java5 now_utc; TZ=GMT-3 java5 now_utc
now=2021-01-24 12:56:14 [unix ts=1611492974.264]
now=2021-01-24 12:56:14 [unix ts=1611492974.726]

Upvotes: 0

Thomas Fritsch
Thomas Fritsch

Reputation: 10147

An Instant object and also a Date object by themselves only contain a point in time, but no timezone information. Furthermore, the toString() method of the Date class implicitly chooses the timezone provided by the system environment, which is not what you want.

Therefore you need to chose the timezone (in your case UTC) explicitly. For example like this:

Instant instant = Instant.now();
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.UTC);
System.out.println("Current UTC time is " + offsetDateTime);

This will (independently from the operation system) print

Current UTC time is 2021-01-22T22:37:21.950354100Z

where the trailing Z denotes the zero timezone offset (i.e. UTC).

Upvotes: 2

rzwitserloot
rzwitserloot

Reputation: 103813

suggests that the way to get the UTC timestamp in Java is the following:

Instant.now() // Capture the current moment in UTC.

This, and most answers in this thread, are misleading.

Instant represents an instant in time. It's 'solarflares' time: Absolutely not one iota about it represents anything that is invented by human brains, and UTC is a timezone: A human invention. The cosmos, the sun, astronomy - they have no idea what UTC is, and don't care - and that's what Instant is all about. Instants are devoid of such human concepts as 'hours' or 'days' or 'timezones'. It makes no sense to ask an instant what day it happened on. It cannot tell you; some event occurred: If I ask a russian from the 19th century when that happened, they'll likely give a completely different answer vs. if I ask someone living a mere 100 miles west, for example. Instant doesn't know which localization to apply and thus doesn't let you ask it this question - that's a good thing, objects should not expose methods to which any answer it gives is either gobbledygook or at least requires knowing about all sorts of surprising caveats.

Crucially, if you tell me '... in UTC', you surely can tell with exacting detail which month, which day, etcetera. And Instant does not do this, which is why it is misleading to say that a java.time.Instant represents a moment of time in UTC. It doesn't. It represents a moment in time (not in any particular timezone).

Yeah, internally Instant, just like Date, is just a light wrapper around what System.currentTimeMillis() returns: "millis since epoch", but the crucial thing to understand about it, is that 'UTC' is not part of what it means, and therefore, when you give an Instant instance to some other method (such as System.out.println, to a database via JDBC, etc), that method is under absolutely no obligation to assume that UTC is semantically relevant.

When you want to mix human notions of time keeping (years, days, months, hours, minutes, milliseconds, and, yeah, timezones) with the notion of a more or less absolute* time, the right answer is java.time.ZonedDateTime. Note that any representation of time in something that isn't java.time.* based is by definition broken, as it is in most programming languages - turns out time is a lot more complex than most takes on a library to represent it realize. The fact that java.time is in effect the 4th attempt at writing a time library should be ample indication that it's hard to get it right.

ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC);

THAT is what you want - that isn't just implementation-detail-wise what you want, but it is code that exactly describes what you mean: Right now, at the UTC time zone, stored in an object that semantically doesn't just store the right time but also stores, and tightly entangles into its very identity, that it is specifically in UTC and is not to be re-interpreted, moved to the local zone, or any other such shenanigans - at least, not unless you explicitly ask it to do so.

Date currentUtcTime = Date.from(Instant.now());

Note that Date is the old API and therefore necessarily broken. In this case, Date is a lying liar who lies - it doesn't represent a date, it represents an instant; it is badly named. (The second API is Calendar, also broken. For example, that is also a lying liar who lies: It doesn't represent a Calendar whatsoever. It represents some bizarre amalgamation of a zoned datetime and an instant and is fit to represent neither as a consequence). Any time you go to the Date API weirdness ensues, and something as simple as 'I just want the concept of the time, at some specific moment, in UTC' isn't possible in these APIs. You are now dependent on barely defined behaviour of all the various libraries up and down the chain - you're effectively stuck praying that they do the right thing, or delving into exotic settings to try to cajole these libraries into doing what you want.

TL;DR: Use java.time.

*) Note that ZonedDateTime is not absolute. For example, if you have the time January 20th, 2023, 8 in the morning, at Europe/Amsterdam, in the form of a ZonedDateTime object, then the amount of seconds that will pass between now and that moment sure seems like it does not change and will not change when e.g. amsterdam goes through an hour change due daylight savings. However, if the dutch government decrees that henceforth The Netherlands will no longer move the clocks at all and will stay in summer time forever (which is likely - EU directive is already in place, it's now just a matter of when), then at the moment the gavel lands, your appointment shifts by 1 hour exactly.

That hopefully provides crucial insight in the difference: Instant, representing events (hence why I like to call it 'solarflares time', to disentangle it from human time keeping concepts as much as possible), doesn't even understand the very concept of such a decision having an effect on things. ZonedDateTime on the other hand is inherently bound up in it - hence the Zone in ZonedDateTime.

If you want to store barber appointments and use Instant to do it, you WILL be an hour late or early sooner rather than later.

Upvotes: 3

Basil Bourque
Basil Bourque

Reputation: 340098

Your code:

Date.from(Instant.now())

You are mixing the terrible legacy classes with their replacement, the modern java.time classes.

Don’t.

Never use Date. Certainly no need to mix with java.time.Instant.

To explain your particular example, understand that among the Date class’ many poor design choices is the anti-feature of its Date#toString method implicitly applying the JVM’s current default time zone while generating its text.

You ran your code on two different JVMs that had different current default time zones. So you got different outputs.

Sun, Oracle, and the JCP gave up on the legacy date-time classes. So should we all. I recommend you not spend time trying understand Date, Calendar, SimpleDateFormat, and such.

You asked:

Question: How do we display the UTC timestamp in a Java program?

Instant.now().toString()

See that code run live at IdeOne.com.

2021-01-22T21:50:18.887335Z

You said:

On Windows: …

On Linux: …

You’ll get the same consistent results from Instant.now().toString() across Windows, Linux, BSD, macOS, iOS, Android, AIX, and so on.


Here is a table I made to guide you in transitioning from the legacy classes.

enter image description here

Upvotes: 18

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79580

The java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). When you print an object of java.util.Date, its toString method returns the date-time in the JVM's timezone, calculated from this milliseconds value. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFormat and obtain the formatted string from it.

I would suggest you simply use Instant.now() which you can convert to other java.time type.

The date-time API of java.util 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.

However, if you still want to use java.util.Date, use SimpleDateFormat as mentioned above.

Demo:

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) {
        Date currentUtcTime = Date.from(Instant.now());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
        sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        System.out.println("Current UTC time is " + sdf.format(currentUtcTime));
    }
}

Output:

Current UTC time is 2021-01-22 21:53:07 UTC

Upvotes: 7

Related Questions