The calendaric calculations are based on the rules of the proleptic Gregorian calendar as specified in ISO 8601. Leap seconds are ignored.
Internally, the time is stored as an
Int64 representing seconds from epoch
0001-01-01 00:00:00.0 UTC) and an
nanosecond-of-second with value range
The supported date range is
0001-01-01 00:00:00.0 to
9999-12-31 23:59:59.999_999_999 in any local time zone.
There are several methods to retrieve a
Time instance representing the
Time.utc # returns the current time in UTC Time.local Time::Location.load("Europe/Berlin") # returns the current time in time zone Europe/Berlin Time.local # returns the current time in current time zone
It is generally recommended to keep instances in UTC and only apply a local time zone when formatting for user display, unless the domain logic requires having a specific time zone (for example for calendaric operations).
Time instances representing a specific instant can be created by
.new with the date-time specified as individual arguments:
time = Time.utc(2016, 2, 15, 10, 20, 30) time.to_s # => 2016-02-15 10:20:30 UTC time = Time.local(2016, 2, 15, 10, 20, 30, location: Time::Location.load("Europe/Berlin")) time.to_s # => 2016-02-15 10:20:30 +01:00 Europe/Berlin # The time-of-day can be omitted and defaults to midnight (start of day): time = Time.utc(2016, 2, 15) time.to_s # => 2016-02-15 00:00:00 UTC
Time instance allows querying calendar data:
time = Time.utc(2016, 2, 15, 10, 20, 30) time.year # => 2016 time.month # => 2 time.day # => 15 time.hour # => 10 time.minute # => 20 time.second # => 30 time.millisecond # => 0 time.nanosecond # => 0 time.day_of_week # => Time::DayOfWeek::Monday time.day_of_year # => 46 time.monday? # => true time.time_of_day # => 10:20:30
For querying if a time is at a specific day of week,
Time offers named
predicate methods, delegating to
time.monday? # => true # ... time.sunday? # => false
Each time is attached to a specific time zone, represented by a
#zone returns the time zone observed in this location at the current time
(i.e. the instant represented by this
#offset returns the offset of the current zone in seconds.
time = Time.local(2018, 3, 8, 22, 5, 13, location: Time::Location.load("Europe/Berlin")) time # => 2018-03-08 22:05:13 +01:00 Europe/Berlin time.location # => #<Time::Location Europe/Berlin> time.zone # => #<Time::Location::Zone CET +01:00 (3600s) STD> time.offset # => 3600
.utc, the location is
time = Time.utc(2018, 3, 8, 22, 5, 13) time # => 2018-03-08 22:05:13.0 UTC time.location # => #<Time::Location UTC> time.zone # => #<Time::Location::Zone UTC +00:00 (0s) STD> time.offset # => 0
Time instance can be transformed to a different time zone while retaining
the same instant using
time_de = Time.local(2018, 3, 8, 22, 5, 13, location: Time::Location.load("Europe/Berlin")) time_ar = time_de.in Time::Location.load("America/Buenos_Aires") time_de # => 2018-03-08 22:05:13 +01:00 Europe/Berlin time_ar # => 2018-03-08 18:05:13 -03:00 America/Buenos_Aires
Time instances show a different local date-time, but they represent
the same date-time in the instant time-line, therefore they are considered
time_de.to_utc # => 2018-03-08 21:05:13 UTC time_ar.to_utc # => 2018-03-08 21:05:13 UTC time_de == time_ar # => true
There are also two special methods for converting to UTC and local time zone:
time.to_utc # equals time.in(Location::UTC) time.to_local # equals time.in(Location.local)
#to_local_in allows changing the time zone while keeping
the same local date-time (wall clock) which results in a different instant
on the time line.
To make date-time instances exchangeable between different computer systems or readable to humans, they are usually converted to and from a string representation.
#to_s formats the date-time according to a specified pattern.
time = Time.utc(2015, 10, 12, 10, 30, 0) time.to_s("%Y-%m-%d %H:%M:%S %:z") # => "2015-10-12 10:30:00 +00:00"
Time.parse! are used to construct a
Time instance from date-time
information in a string, according to a specified pattern:
Time.parse("2015-10-12 10:30:00 +00:00", "%Y-%m-%d %H:%M:%S %z", Time::Location::UTC) Time.parse!("2015-10-12 10:30:00 +00:00", "%Y-%m-%d %H:%M:%S %z")
Time::Format for all directives.
Time.utc(2015, 10, 10) - 5.days # => 2015-10-05 00:00:00 +00:00 span = Time.utc(2015, 10, 10) - Time.utc(2015, 9, 10) span.days # => 30 span.total_hours # => 720 span.total_minutes # => 43200
The typical time representation provided by the operating system is based on a "wall clock" which is subject to changes for clock synchronization. This can result in discontinuous jumps in the time-line making it not suitable for accurately measuring elapsed time.
Time are focused on telling time – using a "wall clock".
Time.local is called multiple times, the difference between the
returned instances is not guaranteed to equal to the time elapsed between
making the calls; even the order of the returned
Time instances might
not reflect invocation order.
t1 = Time.utc # operation that takes 1 minute t2 = Time.utc t2 - t1 # => ?
Time::Span could be anything, even negative, if the
computer's wall clock has changed between both calls.
As an alternative, the operating system also provides a monotonic clock. Its time-line has no specified starting point but is strictly linearly increasing.
This monotonic clock should always be used for measuring elapsed time.
A reading from this clock can be taken using
t1 = Time.monotonic # operation that takes 1 minute t2 = Time.monotonic t2 - t1 # => 1.minute (approximately)
The execution time of a block can be measured using
elapsed_time = Time.measure do # operation that takes 20 milliseconds end elapsed_time # => 20.milliseconds (approximately)