System.currentTimeMillis vs System.nanoTime
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
System.currentTimeMillis() and System.nanoTime() both return numbers related to time, but they answer different questions. One is for wall-clock timestamps, and the other is for measuring elapsed time.
Choosing the wrong one can lead to subtle bugs. A benchmark based on currentTimeMillis() can be distorted by clock changes, while a timestamp based on nanoTime() is meaningless outside the current JVM process.
Use currentTimeMillis() for Real-World Time
System.currentTimeMillis() returns the current wall-clock time as milliseconds since the Unix epoch. That makes it suitable for:
- logging timestamps
- storing event times
- comparing against real dates and times
The important limitation is that wall-clock time can move. NTP synchronization, manual clock changes, leap adjustments, and VM time changes can all affect the value.
That is why currentTimeMillis() is not the best timer for measuring how long code took to run.
Use nanoTime() for Elapsed Time
System.nanoTime() is designed for measuring durations. It uses a monotonic time source with an arbitrary origin, so only differences between two readings are meaningful.
This is the right choice for:
- microbenchmarks
- timeout calculations
- profiling short operations
Even though the method name says "nano," it does not guarantee true nanosecond precision. It simply returns time in nanosecond units with the best timer the platform provides.
Why the Difference Matters
Suppose you measure a timeout using wall-clock time:
If the system clock jumps backward, this loop may run longer than intended. If the clock jumps forward, it may finish too early.
The monotonic form is safer for durations:
Because nanoTime() is monotonic, it is much better suited for elapsed-time logic.
Benchmarking Caveat
Even though nanoTime() is the right primitive for measuring durations, simple hand-written benchmarks can still be misleading because of JIT warmup, dead-code elimination, and GC pauses. For serious benchmarking in Java, libraries such as JMH exist for a reason.
The important point is still the same: if you measure elapsed time manually, nanoTime() is the correct clock source. currentTimeMillis() is a timestamp source, not a benchmarking tool.
A Simple Rule of Thumb
Ask yourself what you need:
- "What time did this happen?" Use
currentTimeMillis(), or better yetInstant.now(). - "How long did this take?" Use
nanoTime().
That simple distinction covers most cases. The methods are not interchangeable even though both return long.
If you remember only one rule from this topic, remember that timestamps are about real-world chronology and durations are about monotonic differences. Java gives you a different clock source for each because they solve different problems well.
That distinction prevents many subtle timing bugs.
Common Pitfalls
- Using
currentTimeMillis()for benchmarking or timeout measurement. - Treating
nanoTime()as a wall-clock timestamp. - Comparing
nanoTime()values across JVM restarts or different machines. - Assuming
nanoTime()implies true hardware nanosecond resolution.
Summary
- '
currentTimeMillis()gives wall-clock time since the Unix epoch.' - '
nanoTime()gives a monotonic time source for measuring elapsed time.' - Use wall-clock time for timestamps and monotonic time for durations.
- '
nanoTime()values only make sense when subtracted from each other.' - For modern timestamp APIs,
Instant.now()is often clearer than raw epoch milliseconds.
Related reading
- System.OutOfMemoryException when generating permutations
- Table 'performance_schema.session_variables' doesn't exist
- TableView slow when adding images to cellForRowAtIndex
- Tail Recursion optimization for JavaScript?
- System.out.println shortcut on Intellij IDEA
- Take n random elements from a ListE?
- TargetedPatchingOptOut Performance critical to inline across NGen image boundaries?
- Task.WhenAll vs Parallel.ForEachAsync - Which approach is best and why?

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.