Monotonic time

System Clock

The operation system comes with many clocks, real time (system-wide clock), monotonic, boot time, process cpu time, thread cpu time. When we do Time.now, it retrives time from the System clock (Note: System clock measures real (i.e., wall-clock) time).

System clock changes regularly:

This clock is affected by discontinuous jumps in the system time
(e.g., if the system administrator manually changes the
clock), and by the incremental adjustments performed by
adjtime and NTP.

See CLOCK_REALTIME

So we shouldn't rely on system clock to do any task involves time measurement. Good news is operation system comes with another clock: Monotonic clock.

Monotonic Clock

Monotonic Clock cannot be set and represents monotonic time since some unspecified starting point. Monotonic Clock is not affected by discontinuous jumps in the system time (e.g., if the system administrator manually changes the clock), but STILL affected by adjtime(3) and NTP.

Usage of Monotonic time

Precise and reliable time measurements.

Use Monotonic time in CRuby

Process.clock_gettime(Process::CLOCK_MONOTONIC)

if you're on Linux 2.6.28+ or macOS 10.12+, you can also use:

Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW)

It‘s similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time, that is not subject to NTP adjustments or the incremental adjustments performed by adjtime(3).

For more information, please see Ruby‘s Process.clock_gettime docs and clock_getres(2).

Use Monotonic time in JRuby

java.lang.System.nanoTime()

What gems to use?

There is a Monotonic gem, but it is not using Monotonic time and it doesn't work for JRuby.

However, if you're looking for full feature native implementation across all platforms, checkout Hitimes!

HiTimes

Hitimes is a fast, high resolution timer library for recording performance metrics. The time measurements returned in nanoseconds.

MonotonicTime

MonotonicTime wraps hitimes to return measurements in seconds: MonotonicTime.

Drop-in module

But I think you wouldn‘t want to introduce a dependency in your project. You can use this pure ruby drop-in module in your application, it‘s based on concurrent-ruby‘s implementation that works for CRuby and JRuby.

Monotonic.now # returns monotonic time in *seconds*
Monotonic.time do
  1+1 # measure time elapsed for expression 1+1
end

Testing

You could stubs or allow Monotonic module:

# Minitest
Monotonic.stubs(:now).returns(t)

# RSpec
allow(Monotonic).to receive(:now) { t }

Replace Timecop with Monotonic Time

See this Pull Request for example: stripe/stripe-ruby#857.

Cheers,
Juanito