31

In Java, we can have many different ways to get the current timestamp, but which one is recommended: Instant.now().toEpochMilli() or System.currentTimeMillis()

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Yishu Fang
  • 9,448
  • 21
  • 65
  • 102
  • 3
    Define better? More performant? I bet they perform the same. More readable? That's just opinion. However, I **think** both are better than `Calendar.getInstance().getTimeInMillis()` – Elliott Frisch Nov 05 '19 at 06:37
  • In terms of performance, `System.currentTimeMillis()` should be quicker because of less overhead (no object creation). In terms of precision, the `Instant`-approach might be better on some platforms when microsecond resolution is supported. – Meno Hochschild Nov 05 '19 at 06:39
  • @ElliottFrisch I have changed the wording :-D – Yishu Fang Nov 05 '19 at 06:39
  • 2
    The real question is why are you getting the timestamp? If you're timing something, then [`System.nanoTime()`](https://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime()) is probably the way to go (if you want *precision*). I *might* look for a higher level abstraction; like [`StopWatch`](https://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/time/StopWatch.html). – Elliott Frisch Nov 05 '19 at 06:44
  • @MenoHochschild how does a microsecond resolution matter, when both constructs will truncate to milliseconds anyway? – Holger Nov 07 '19 at 16:56
  • @Holger The real resolution of `System.currentTimeMillis()` can even be around 10ms or worse. It is also more exposed to clock changes of operating system (like reconnecting to a NPT-Server). – Meno Hochschild Nov 07 '19 at 18:29
  • @MenoHochschild I just re-checked, on my system `Instant.now()` does exactly the same as `Instant.ofEpochMilli(System.currentTimeMillis())`. There’s no resolution difference, but more important, there is no semantic difference. Now, which part of the specifications says, that a system with a better clock may improve the resolution of `Instant`, but is obliged to keep `System.currentTimeMillis()` at a lower resolution? – Holger Nov 08 '19 at 09:18
  • @Holger Maybe you have looked at Java 8, but Java 9 uses a possibly more precise clock, dependent on the platform. See also this [SO-post](https://stackoverflow.com/q/33477695/2491410). In Java 9: `Instant.now()` is equivalent to `Clock.systemUTC().instant()`. And that clock was changed, see also [OpenJDK-log](https://bugs.openjdk.java.net/browse/JDK-8068730) – Meno Hochschild Nov 08 '19 at 11:05
  • @Holger Here the new Java-9 [implementation](http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/ca7fb78b94b6/src/java.base/share/classes/java/time/Clock.java#l521). It is no longer based on `System.currentTimeMillis()` only. – Meno Hochschild Nov 08 '19 at 11:09
  • @MenoHochschild but the nanosecond resolution is irrelevant when the OP only asks for `toEpochMilli()`. You didn’t answer the question, why a developer has to assume that `System.currentTimeMillis()` will have a worse than milliseconds resolution, even when the system has a better clock and the same JRE provides that better resolution through a semantically equivalent construct. – Holger Nov 08 '19 at 11:52
  • @Holger No, both expressions are no longer equivalent in Java-9 or later. The produced resulting numbers/instants, even after truncation to millisecond precision in both cases and displaying only milliseconds will be usually different. However, my English is not perfect, maybe we should use the term accuracy instead of precision. Personally I don't worry so much about it because it is a very small difference, often smaller than 10 ms. Maybe it helps you to understand the difference when you imagine that both approaches use DIFFERENT clocks of the underlying operating system. – Meno Hochschild Nov 08 '19 at 11:56
  • @MenoHochschild I understand that in that implementation both constructs use different clocks yielding different precision, but that would be easy to fix, e.g. by implementing `System.currentTimeMillis()` as `return Instant.now().toEpochMilli();` or some internal construct using the same clock as `Instant`. As long as *the specification* doesn’t forbid this, the fact that one has less precision than the other seems to be a flaw of one particular implementation. – Holger Nov 08 '19 at 12:20
  • @Holger The [spec](https://docs.oracle.com/javase/9/docs/api/java/time/Clock.html#systemUTC--) is somehow vague, but does not exclude a difference between `System.currentTimeMillis()` and a higher-precision clock. Furthermore, `System.currentTimeMillis()` cannot be implemented as redirecting to `Instant.now().toEpochMilli()` (which also uses `System.currentTimeMillis()`) because then we have a circular logic with the danger of infinite looping - see the Java-9 source code. – Meno Hochschild Nov 08 '19 at 12:30

4 Answers4

17

Both are fine. And neither is recommended except for a minority of purposes.

What do you need milliseconds since the epoch for?

In Java, we can have many different ways to get the current timestamp,

For current timestamp just use Instant.now(). No need to convert to milliseconds.

Many methods from the first years of Java, also many in the standard library, took a long number of milliseconds since the epoch as argument. However, today I would consider that old-fashioned. See if you can find — or create — or more modern method that takes for instance an Instant as argument instead. Go object-oriented and don’t use a primitive long. It will make your code clearer and more self-explanatory.

As Eliott Frisch said in a comment, if this is for measuring elapsed time, you may prefer the higher resolution of System.nanoTime().

If you do need milliseconds since the epoch

Assuming that you have good reasons for wanting a count of milliseconds since the epoch, …

which one is recommended: Instant.now().toEpochMilli() or System.currentTimeMillis()[?]

Opinions differ. Some will say that you should use java.time, the modern date and time API, for all of your date and time work. This would imply Instant here. Unsg java.time is generally a good habit since the date and time classes from Java 1.0 and 1.1 (Date, Calendar, TimeZone, DateFormat, SimpleDateFormat and others) are poorly designed and now long outdated, certainly not any that we should use anymore. On the other hand I am not aware of any design problem with System.curremtTimeMillis() in particular (except what I mentioned above about using a long count of milliseconds at all, which obviously is intrinsic to both Instant.now().toEpochMilli() and System.currentTimeMillis()).

If there is a slight performance difference between the two, I have a hard time imagining the situation where this will matter.

Take the option that you find more readable and less surprising in your context.

Similar questions

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 3
    I would add that one other advantage to Instant.now() is that you can mock it with a tool like JMockit. System.currentTimeMillis() is a native method and thus usually unmockable. – fool4jesus Jun 04 '21 at 17:43
  • For low latency java; using primitive data types like "long" is much better. Using Long class is expensive and holds more bytes in memory; and creates more garbage. Less garbage means high peformance. More garbage means high latency. – alpha Oct 21 '22 at 18:25
  • 1
    @alpha marginally better indeed, but *much* better? Can’t imagine. Have you got any measurements to support your claim? Java is very good at garbage collecting short-lived objects. I agree, if you are really going after micro-optimization, there is a little potential here. (And I am in no way suggesting the use of any `Long` objects.) – Ole V.V. Oct 21 '22 at 18:40
  • Yep I did do some performance tests on primitives vs Boxed objects. i.e. methods calls uses stack memory if you use primitives, thus no garbage created. Boxed objects are stored in heap.. also an array of long are allocated in the same block of memory, where as array of Long are not – alpha Nov 05 '22 at 03:19
5

As per my understanding Instant.now().toEpochMilli() is better as Java-8 onward usage of Instant has been recommended.

Also, it works based on timeline and instant represents a specific moment on that timeline.

In case of java.lang.System.currentTimeMillis() method it returns the current time in milliseconds. The granularity of the value depends on the underlying operating system and may be larger.

Hence, to be consistent altogether use Instant.

Vinay Prajapati
  • 7,199
  • 9
  • 45
  • 86
4

For what it's worth, I've done a quick non-ideal performance test comparing the two methods.

On my system (Ubuntu 20.04, OpenJDK 17.0.4), running System.currentTimeMillis ten million times takes cca 230ms while running Instant.now().toEpochMilli() ten million times takes cca 370ms.

import java.time.Instant;

public class A { 
   public static void main(String[] args) {
       long a = 0;
       long start = System.currentTimeMillis();
       for (int i = 0; i < 10_000_000; i++) {
           //a += Instant.now().toEpochMilli();
           a += System.currentTimeMillis();
       }
       System.out.println(a);
       System.out.println(System.currentTimeMillis() - start);
   }   
}
Rok Povsic
  • 4,626
  • 5
  • 37
  • 53
3

I want to add that System.nanoTime() is less about precision but more about accuracy.

System.currentTimeMillis() is based on the system clock, which is, most of the time, based on a quartz clock inside a computer. It is not accurate and it drifts. (VM is even worse since you don't have a physical clock and have to sync with the host) When your computer syncs this quartz clock with a global clock, you might even observe your clock jumps backward/forward because your local clock is too fast or slow.

On the other hand, System.nanoTime() is based on a monotonic clock. This clock has nothing to do with the actual time we humans speak. It only moves forward at a constant pace. It does not drift like the quartz clock and there is no sync required. This is why it is perfect for measuring elapses.

Chris Peng
  • 896
  • 1
  • 10
  • 23