37

The default java.time.Clock implementation is based on System.currentTimeMillis(). As discussed for example here, Monotonically increasing time in Java?, it is not guaranteed to be monotonic.

And indeed, I regularly experience a situation, where the system time is automatically adjusted a few seconds to the past, and the java clock jumps back too.

//now() returns 2016-01-13T22:34:05.681Z
order.setCreationTime(Instant.now());

//... something happens, order gets cancelled

//now() returns 2016-01-13T22:34:03.123Z
//which is a few seconds before the former one,
//even though the call was performed later - in any reasonable sense.
//The recorded history of events is obviously inconsistent with the real world.
order.setCancelationTime(Instant.now());

It is then impossible to perform time-sensitive things, like recording and analysing event history, when one can not rely on time going only in one direction.

The aforementioned post says that System.nanoTime() is monotonic (if the underlying system supports it). So, if I want to base my code on the java.time API, I would need Clock that uses nanoTime internally to ensure one-way flow of the time. Maybe something like this would work. Or would't it?

public class MyClock() extends java.time.Clock {

    private final long adjustment;

    public MyClock() {
        long cpuTimeMillis = System.nanoTime()/1000000;
        long systemTimeMillis = System.currentTimeMillis();
        adjustment = systemTimeMillis - cpuTimeMillis;
    }

    @Override
    public long millis() {
        long currentCpuTimeMillis = System.nanoTime()/1000000;
        return currentCpuTimeMillis + adjustment;
    }
}   

It is just a sketch, not a full Clock implementation. And I suppose a proper implementation should also perform the adjustment against another Clock passed in the constructor, rather than directly against the currentTimeMillis().

Or, is there already such a monotonic Clock implementation available anywhere? I would guess there must have been many people facing the same issue.

Conclusion

Thanks for the inspiring comments and answers. There are several interesting points scattered across the comments, so I will summarize it here.

1. Monotonic clock

As for my original question, yes, it is possible to have monotonic clock that is not affected by system time jumping backwards. Such implementation can be based on System.nanoTime() as I suggested above. There used to be problems with this aproach in the past, but it should work fine on today's modern systems. This approach is already implemented for example in the Time4J library, their monotonic clock can be easily converted to java.time.Clock:

Clock clock = TemporalType.CLOCK.from(SystemClock.MONOTONIC);

2. Proper system time control

It it possible to configure system time management (ntpd in unix/linux), so that the system time virtually never moves back (it gets just slowed down if necessary), then one can rely on the system time being monotonic, and no clock-magic is necessary in Java.

I will go this way, as my app is server-side and I can get the time under control. Actually, I experienced the anomalies in an experimental environment that I installed myself (with only superficial knowledge of the domain), and it was using just ntpdate client (which can jump backwards if the time is out of sync), rather than ntpd (which can be configured so that it does not jump back).

3. Using sequences rather than clock

When one needs to track a strong relation what happened before what, it is safer to give the events serial numbers from an atomically generated sequence and not rely on the wall clock. It becomes the only option once the application is running on several nodes (which is not my case though).

Community
  • 1
  • 1
Jan X Marek
  • 2,464
  • 2
  • 18
  • 26
  • 3
    Although time is a monotonic thing, dates are not. Dates are a human construction to represent time. If you need something to represent time purely, maybe you could use a database sequence or any other reliable information instead. – Leo Jan 13 '16 at 23:11
  • 1
    nanoTime may not do what you need it to do. http://www.principiaprogramatica.com/?p=16 – BillRobertson42 Jan 14 '16 at 02:33
  • 1
    You might be able to study the source of my [monotonic clock implementation](http://time4j.net/javadoc-en/net/time4j/SystemClock.html#MONOTONIC) in order to transfer some ideas to your java.time-based clock. Source - see: https://github.com/MenoData/Time4J/blob/master/core/src/main/java/net/time4j/SystemClock.java – Meno Hochschild Jan 14 '16 at 04:56
  • 4
    Or you could even simply import my library Time4J and use `Clock clock = TemporalType.CLOCK.from(SystemClock.MONOTONIC);` Done. – Meno Hochschild Jan 14 '16 at 05:07
  • @Meno Hochschild: Thanks for the link, it looks like a supercool library. I see you are doing there the same kind of adjustment as in my code snippet, plus a few more subtle things. – Jan X Marek Jan 14 '16 at 10:45
  • 1
    @Bill, that article is from 2008, a lot has changed since then. – the8472 Jan 14 '16 at 13:26
  • @the8472 That's good to hear. Do you have a link where I can read about it? Would really appreciate it. – BillRobertson42 Jan 14 '16 at 14:03
  • 2
    @Bill on x86 current hotspot versions check for the [invariant_tsc](https://en.wikipedia.org/wiki/Time_Stamp_Counter) CPU flag and use that where available. – the8472 Jan 14 '16 at 14:36
  • 3
    Not entirely sure what your application is, but you might look into the concept of Lamport time. – chrylis -cautiouslyoptimistic- Jan 15 '16 at 14:26
  • 1
    Note that in distributed environments nodes can keep track of the last "timestamp" received from each other node, allowing nodes to use their own arbitrary "timing" algorithm, so long as they're individually monotonic. So you can use a separate `AtomicLong` on every node, you just need to record what the last value received from every other node was. In a heavily distributed (or heavily redundant) system this is preferable to the bottleneck of a single shared atomic sequence. – biziclop Jan 15 '16 at 14:31
  • 1
    FYI, the java.time.* clock was updated in Java 9 to be more accurate: https://bugs.openjdk.java.net/browse/JDK-8068730 – JodaStephen Sep 10 '18 at 08:44

2 Answers2

8

As @the8472 says, the key is to have the time synchronization on the machine (where the jvm runs) correct.

If you program a client then it really can be dangerous to rely on the system clocks. But for servers, there is a solution - you might want to consider using NTP with strict configuration.

In here they basicly explain that NTP will slow down the time and not set it backwards.

And this NTP documentation says :

Sometimes, in particular when ntpd is first started, the error might exceed 128 ms. This may on occasion cause the clock to be set backwards if the local clock time is more than 128 s in the future relative to the server. In some applications, this behavior may be unacceptable. If the -x option is included on the command line, the clock will never be stepped and only slew corrections will be used.

Community
  • 1
  • 1
Milos Gregor
  • 940
  • 8
  • 14
3

Do note that nanoTime may increase monotonically but it does not relate nicely to wall time, e.g. due to hibernation events, VM suspension and similar things.

And if you start distributing things across multiple servers then synchronizing on currentMillis may also bite you again due to clock drift.

Maybe you should consider getting the system time of your servers under control.

Or track relative sequence of the events separately from the time at which they were supposedly recorded.

the8472
  • 40,999
  • 5
  • 70
  • 122
  • 2
    I don't think "consider getting the system time of your servers under control" is actually practical; but if you have some example of multi-region datacenters managing it I'd like to know more. – dlamblin Mar 21 '18 at 03:14
  • @dlamblin You mean like amazon's time sync and google's truetime. Basically GPS receivers + backup atomic clocks available in each data center. So their time sources are very accurate and globally synchronized. But you still need to ensure that individual machines stay slaved to it with sufficient accuracy. – the8472 Mar 21 '18 at 23:45
  • Thanks. That's basically NTPd with a local, accurately synchronized clock? Okay. When I said "practical" I assumed the person didn't have the resources of an Amazon or Google to do this perfectly, and similarly wasn't in a client relationship to some system that had already solved it. – dlamblin Mar 26 '18 at 12:11
  • @dlamblin you don't have to be google, but yes, it would be a non-trivial expense and software solutions like vector clocks would probably be preferable when possible. I'm just saying that it can be done if it's a critical requirement for an application. – the8472 Mar 26 '18 at 17:09