Reputation: 13407
In Java, what are the performance and resource implications of using
System.currentTimeMillis()
vs.
new Date()
vs.
Calendar.getInstance().getTime()
As I understand it, System.currentTimeMillis()
is the most efficient. However, in most applications, that long value would need to be converted to a Date or some similar object to do anything meaningful to humans.
Upvotes: 265
Views: 166051
Reputation: 339303
Update: This old Question deserves a new Answer. Times have changed. (See what I did there?)
Instant.now()
in modern Java to capture the current moment with a resolution of microseconds, as seen with a zero offset-from-UTC. This is very fast (25 nanos), and should be your first thought when writing business logic code.System.nanoTime
for benchmarks.A crude less-than-trustworthy test shows a matter of mere nanoseconds.
Method call | Nanoseconds (approximate) |
---|---|
Instant.now() |
25 |
System.currentTimeMillis() |
16 |
System.nanoTime() |
11 |
System.currentTimeMillis() vs. new Date() vs. Calendar.getInstance().getTime()
Those two classes, java.util.Date
& java.util.Calendar
are both terribly flawed. They were supplanted by the modern java.time classes in Java 8+, as defined in JSR 310. Avoid both of these classes like the plague.
If handed an object of either class, immediately convert to the modern replacement. Use new to…
/from…
conversion methods added to the old classes.
java.time.Instant
replaces java.util.Date
.java.time.ZonedDateTime
replaces GregorianCalendar
, the commonly used subclass of Calendar
.To capture the current moment as seen with an offset from UTC of zero hours-minutes-seconds, use java.time.Instant
.
Instant instant = Instant.now() ;
A Instant
object is capable of representing nanoseconds. In Java 9+, you will likely see the current moment captured in microseconds, due to a fresh implementation of Clock
. In Java 8 specifically, you will see the current moment captured in mere milliseconds (the same as java.util.Date
).
First of all, do not fall into the trap of premature optimization. In a common business app, capturing the current moment is going to be utterly insignificant to the performance of your app.
For a business app, you should generally be making this simple call: Instant.now()
.
If the time zone is important to your business logic, use ZonedDateTime.now( … )
. Or, less commonly, OffsetDateTime.now( … )
.
System.nanoTime
Secondly, if you are trying to write benchmarks, do not use any of these methods and classes.
For benchmarking, you should be using System.nanoTime
to get a count of nanoseconds elapsed since some unspecified moment (likely the moment when the computer booted). The nanoTime
method is the simplest, fastest, and most reliable way to determine elapsed time.
The System.nanoTime
method is nothing but a count of elapsed nanoseconds. This method does not do any time-keeping, has no sense of date or time-of-day.
In contrast, the time-keeping methods such as System.currentTimeMillis
, Instant.now()
, OffsetDateTime.now( … )
, and ZonedDateTime.now( … )
are all doing much more work. These methods get the current moment within the context of the epoch reference of first moment of 1970 in UTC, 1970-01-01T00:00Z.
Writing quality benchmarks is actually quite tricky. So read up on the subject. And see JEP 230: Microbenchmark Suite, based on JMH.
And speaking of a poor benchmark, here's my crude attempt at testing the performance of:
Instant.now()
System.currentTimeMillis()
System.nanoTime()
My lousy benchmark code likely does not show us exact number of nanoseconds-per-call, but I am confident that gives a ball-park number that is the maximum (for
-loop has some overhead).
System.out.println( "Now is " + Instant.now( ) ); // Warm-up whatever it takes to do `Instant.now`.
final int LIMIT = 100_000_000;
long start = System.nanoTime( );
for ( int i = 0 ; i < LIMIT ; i++ )
{
// Instant instant = Instant.now( );
// long millis = System.currentTimeMillis();
// long nanos = System.nanoTime();
}
Duration elapsed = Duration.ofNanos( System.nanoTime( ) - start );
long nanosPerInstant = elapsed.toNanos( ) / LIMIT;
System.out.println( "Elapsed nanos: " + String.format( "%,d" , elapsed.toNanos( ) ) );
System.out.println( "Elapsed: " + elapsed );
System.out.println( "nanosPerInstant = " + nanosPerInstant );
Running this in IntelliJ 2024.2, Java 22.0.2, macOS Sonoma 14.6, on MacBook Pro with Apple M1 Pro, 16 gigs of RAM, 10 cores = 2 efficiency + 8 performance.
Running the tests multiple times gave similar results. Below is a random sample of results.
With entire for
-loop commented-out:
Now is 2024-08-13T23:53:39.822755Z
Elapsed nanos: 83
Elapsed: PT0.000000083S
nanosPerInstant = 0
With empty for
-loop:
Now is 2024-08-13T23:54:11.820363Z
Elapsed nanos: 1,691,917
Elapsed: PT0.001691917S
nanosPerInstant = 0
Running Instant.now()
:
Now is 2024-08-13T23:54:35.178127Z
Elapsed nanos: 2,540,932,375
Elapsed: PT2.540932375S
nanosPerInstant = 25
Running System.currentTimeMillis()
:
Now is 2024-08-13T23:55:08.224822Z
Elapsed nanos: 1,634,351,000
Elapsed: PT1.634351S
nanosPerInstant = 16
Running System.nanoTime()
:
Now is 2024-08-13T23:55:56.014178Z
Elapsed nanos: 1,182,222,833
Elapsed: PT1.182222833S
nanosPerInstant = 11
These results would seem to indicate a few things:
for
loop seems not to be eliminated by the compiler, neither when empty nor when having pointless code producing a value that goes unused.System.currentTimeMillis()
call is about half-again as long as System.nanoTime()
. But I expected a bigger difference.Instant.now()
call does take longer. But I doubt those extra 9 nanoseconds will impact any real-life app.Upvotes: 1
Reputation: 29377
Looking at the JDK, innermost constructor for Calendar.getInstance()
has this:
public GregorianCalendar(TimeZone zone, Locale aLocale) {
super(zone, aLocale);
gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
setTimeInMillis(System.currentTimeMillis());
}
so it already automatically does what you suggest. Date's default constructor holds this:
public Date() {
this(System.currentTimeMillis());
}
So there really isn't need to get system time specifically unless you want to do some math with it before creating your Calendar/Date object with it. Also I do have to recommend joda-time to use as replacement for Java's own calendar/date classes if your purpose is to work with date calculations a lot.
Upvotes: 47
Reputation: 105
System.currentTimeMillis()
is obviously the fastest because it's only one method call and no garbage collector is required.
Upvotes: 0
Reputation: 77191
If you're USING a date then I strongly advise that you use jodatime, http://joda-time.sourceforge.net/. Using System.currentTimeMillis()
for fields that are dates sounds like a very bad idea because you'll end up with a lot of useless code.
Both date and calendar are seriously borked, and Calendar is definitely the worst performer of them all.
I'd advise you to use System.currentTimeMillis()
when you are actually operating with milliseconds, for instance like this
long start = System.currentTimeMillis();
.... do something ...
long elapsed = System.currentTimeMillis() -start;
Upvotes: 23
Reputation: 346377
System.currentTimeMillis()
is obviously the most efficient since it does not even create an object, but new Date()
is really just a thin wrapper about a long, so it is not far behind. Calendar
, on the other hand, is relatively slow and very complex, since it has to deal with the considerably complexity and all the oddities that are inherent to dates and times (leap years, daylight savings, timezones, etc.).
It's generally a good idea to deal only with long timestamps or Date
objects within your application, and only use Calendar
when you actually need to perform date/time calculations, or to format dates for displaying them to the user. If you have to do a lot of this, using Joda Time is probably a good idea, for the cleaner interface and better performance.
Upvotes: 270
Reputation: 39
I tried this:
long now = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
new Date().getTime();
}
long result = System.currentTimeMillis() - now;
System.out.println("Date(): " + result);
now = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
System.currentTimeMillis();
}
result = System.currentTimeMillis() - now;
System.out.println("currentTimeMillis(): " + result);
And result was:
Date(): 199
currentTimeMillis(): 3
Upvotes: 3
Reputation: 452
On my machine I tried check it. My result:
Calendar.getInstance().getTime() (*1000000 times) = 402ms new Date().getTime(); (*1000000 times) = 18ms System.currentTimeMillis() (*1000000 times) = 16ms
Don't forget about GC (if you use Calendar.getInstance()
or new Date()
)
Upvotes: 15
Reputation: 639
Depending on your application, you may want to consider using System.nanoTime()
instead.
Upvotes: 7
Reputation: 83918
I prefer using the value returned by System.currentTimeMillis()
for all kinds of calculations and only use Calendar
or Date
if I need to really display a value that is read by humans. This will also prevent 99% of your daylight-saving-time bugs. :)
Upvotes: 12