Time zones and durations

Time with an offset

A Time stores an instant and an offset. The offset is part of the value, not a property of the machine, so a time written with +03:00 prints with that offset until it is converted:

ruby -e 'require "time"; puts Time.new(2026, 11, 5, 12, 0, 0, "+03:00").utc.iso8601'

2026-11-05T09:00:00Z

ruby -e 't = Time.new(2026, 11, 5, 12, 0, 0, "+03:00"); p t.utc_offset; p t.utc; p t.getlocal("-05:00")'

10800 2026-11-05 09:00:00 UTC 2026-11-05 04:00:00 -0500

utc_offset is in seconds, utc returns a copy in UTC, and getlocal returns a copy in the offset given. The instant never changes; only the clock face does.

utc and localtime

Store and exchange UTC; convert for a reader. Time.now is in the machine's zone, and .utc is the same instant in the zone a log wants:

ruby -e 'require "time"; puts Time.now.utc.iso8601'

2026-11-05T00:27:39Z

iso8601 from the time standard library is the format to write: it sorts lexically, it carries the offset, and every language parses it. A timestamp without an offset is ambiguous, and an ambiguous timestamp in a shared log is a bug waiting for the first traveller.

Durations with the monotonic clock

A duration is a different question from a date. For "how long did this take" the right clock is the monotonic one, which never jumps when the system time is adjusted:

ruby -e 'start = Process.clock_gettime(Process::CLOCK_MONOTONIC); sleep 0.2; p (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start).round(3)'

0.2

Process.clock_gettime returns seconds as a float. Subtract two readings for a duration, and use Time.now only when the answer is a date or a timestamp someone reads.

Adding and subtracting time

Adding a number to a Time adds seconds, and subtracting two times gives seconds:

ruby -e 'require "time"; t = Time.new(2026, 11, 5, 12, 0, 0, "+00:00"); p (t + 90).strftime("%H:%M:%S"); p ((t + 90) - t)'

"12:01:30"
90.0

Seconds are not days. A day is 86,400 seconds except twice a year in a zone with daylight saving, when it is 82,800 or 90,000. For calendar arithmetic use Date and its >> operator, which the next lesson covers.

What to watch for

Time.now in a test makes the result depend on the clock. Pass the time in, or freeze it with a helper, so a failure is reproducible.

A duration measured with Time.now can be negative when the clock is corrected. The monotonic clock cannot go backwards, which is why every timing helper uses it.

Next: Parsing and formatting dates

Article author: Arthur Isaev