# struct Time

- Time
- Struct
- Value
- Object

##
Overview

`Time` represents a date-time instant in incremental time observed in a specific time zone.

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:00Z`) and an `Int32` representing nanosecond-of-second with value range `0..999_999_999`.

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.

###
Telling the Time

There are several methods to retrieve a `Time` instance representing the current time:

    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).

###
Creating a Specific Instant

`Time` instances representing a specific instant can be created by `.utc` or `.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"
    # 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"

###
Retrieving Time Information

Each `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 `#day_of_week`:

    time.monday? # => true
    # ...
    time.sunday? # => false

###
Time Zones

Each time is attached to a specific time zone, represented by a `Location` (see `#location`). `#zone` returns the time zone observed in this location at the current time (i.e. the instant represented by this `Time`). `#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

Using `.utc`, the location is `Time::Location::UTC`:

    time = Time.utc(2018, 3, 8, 22, 5, 13)
    time          # => 2018-03-08 22:05:13Z
    time.location # => #<Time::Location UTC>
    time.zone     # => #<Time::Location::Zone UTC +00:00 (0s) STD>
    time.offset   # => 0

A `Time` instance can be transformed to a different time zone while retaining the same instant using `#in`:

    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/Argentina/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/Argentina/Buenos_Aires]

Both `Time` instances show a different local date-time, but they represent the same date-time in the instant time-line, therefore they are considered equal:

    time_de.to_utc     # => 2018-03-08 21:05:13Z
    time_ar.to_utc     # => 2018-03-08 21:05:13Z
    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.

###
Formatting and Parsing Time

To make date-time instances exchangeable between different computer systems or readable to humans, they are usually converted to and from a string representation.

The method `#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"

Similarly, `Time.parse` and `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")

See `Time::Format` for all directives.

###
Calculations

    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

##
Measuring Time

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.

Instances of `Time` are focused on telling time – using a "wall clock". When `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 # => ?

The resulting `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 `.monotonic`:

    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 `.measure`:

    elapsed_time = Time.measure do
      # operation that takes 20 milliseconds
    end
    elapsed_time # => 20.milliseconds (approximately)

##
Included Modules

- Comparable(Time)
- Steppable

##
Defined in:

json/to_json.cr
time.cr
uri/params/to_www_form.cr
yaml/to_yaml.cr

##
Constant Summary

UNIX_EPOCH = `new(unsafe_utc_seconds: 62135596800_i64)`

  This constant is defined as `1970-01-01 00:00:00Z`". Can be used to create a `Time::Span` that represents an Unix Epoch time duration.

      Time.utc - Time::UNIX_EPOCH

##
Constructors

- .local(year : Int32, month : Int32, day : Int32, hour : Int32 = 0, minute : Int32 = 0, second : Int32 = 0, *, nanosecond : Int32 = 0, location : Location = Location.local) : Time

  Creates a new `Time` instance representing the given local date-time in location (defaults to local time zone).

- .local(location : Location = Location.local) : Time

  Creates a new `Time` instance representing the current time from the system clock observed in location (defaults to local time zone).

- .month_week_date(year : Int32, month : Int32, week : Int32, day_of_week : Int32 | DayOfWeek, hour : Int32 = 0, minute : Int32 = 0, second : Int32 = 0, *, nanosecond : Int32 = 0, location : Location = Location.local) : self

  Creates an instance representing the week-th day_of_week in the given year and month.

- .new(ctx : YAML::ParseContext, node : YAML::Nodes::Node)
- .new(pull : JSON::PullParser) : self

  Reads a string from JSON parser as a time formatted according to RFC 3339 or other variations of ISO 8601.

- .new(*, seconds : Int64, nanoseconds : Int32, location : Location)

  Creates a new `Time` instance that corresponds to the number of seconds and nanoseconds elapsed from epoch (`0001-01-01 00:00:00.0`) observed in location.

- .parse(time : String, pattern : String, location : Location) : Time

  Parses a `Time` from time string using the given pattern.

- .parse!(time : String, pattern : String) : Time

  Parses a `Time` from time string using the given pattern.

- .parse_local(time : String, pattern : String) : Time

  Parses a `Time` from time string using the given pattern and `Time::Location.local` as default location

- .parse_rfc2822(time : String) : self

  Parse time format specified by RFC 2822.

- .parse_rfc3339(time : String) : self

  Parse time format specified by RFC 3339 (ISO 8601 profile).

- .parse_utc(time : String, pattern : String) : Time

  Parses a `Time` from time string using the given pattern and `Time::Location::UTC` as default location.

- .unix(seconds : Int) : Time

  Creates a new `Time` instance that corresponds to the number of seconds elapsed since the Unix epoch (`1970-01-01 00:00:00Z`).

- .unix_ms(milliseconds : Int) : Time

  Creates a new `Time` instance that corresponds to the number of milliseconds elapsed since the Unix epoch (`1970-01-01 00:00:00Z`).

- .unix_ns(nanoseconds : Int) : Time

  Creates a new `Time` instance that corresponds to the number of nanoseconds elapsed since the Unix epoch (`1970-01-01 00:00:00Z`).

- .utc(year : Int32, month : Int32, day : Int32, hour : Int32 = 0, minute : Int32 = 0, second : Int32 = 0, *, nanosecond : Int32 = 0) : Time

  Creates a new `Time` instance representing the given date-time in UTC.

- .utc : Time

  Creates a new `Time` instance representing the current time from the system clock in UTC.

- .utc(*, seconds : Int64, nanoseconds : Int32) : Time

  Creates a new `Time` instance that corresponds to the number of seconds and nanoseconds elapsed from epoch (`0001-01-01 00:00:00Z`) in UTC.

- .week_date(year : Int32, week : Int32, day_of_week : Int32 | DayOfWeek, hour : Int32 = 0, minute : Int32 = 0, second : Int32 = 0, *, nanosecond : Int32 = 0, location : Location = Location.local) : self

  Creates an instance specified by a commercial week date consisting of ISO calendar year, week and a day_of_week.

##
Class Method Summary

- .days_in_month(year : Int, month : Int) : Int32

  Returns the number of days in month (value range: `1..12`) taking account of the year.

- .days_in_year(year : Int) : Int32

  Returns the number of days in year.

- .leap_year?(year : Int) : Bool

  Returns `true` if year is a leap year in the proleptic Gregorian calendar.

- .measure(&) : Time::Span

  Measures the execution time of block.

- .monotonic : Time::Span

  Returns a reading from the monotonic clock to measure elapsed time.

- .parse_iso8601(time : String)

  Parse datetime format specified by ISO 8601.

##
Instance Method Summary

- #+(span : Time::Span) : Time

  Returns a copy of this `Time` with span added.

- #+(span : Time::MonthSpan) : Time

  Returns a copy of this `Time` with span added.

- #-(other : Time) : Time::Span

  Returns a `Time::Span` amounting to the duration between other and `self`.

- #-(span : Time::Span) : Time

  Returns a copy of this `Time` with span subtracted.

- #-(span : Time::MonthSpan) : Time

  Returns a copy of this `Time` with span subtracted.

- #<=>(other : Time) : Int32

  Compares this `Time` with other.

- #==(other : Time) : Bool

  Compares this `Time` with other for equality.

- #at_beginning_of_day : Time

  Returns a copy of this `Time` representing the beginning of the day.

- #at_beginning_of_hour : Time

  Returns a copy of this `Time` representing the beginning of the hour.

- #at_beginning_of_minute : Time

  Returns a copy of this `Time` representing the beginning of the minute.

- #at_beginning_of_month : Time

  Returns a copy of this `Time` representing the beginning of the month.

- #at_beginning_of_quarter : Time

  Returns a copy of this `Time` representing the beginning of the quarter.

- #at_beginning_of_second : Time

  Returns a copy of this `Time` representing the beginning of the seconds.

- #at_beginning_of_semester : Time

  Returns a copy of this `Time` representing the beginning of the semester.

- #at_beginning_of_week(start_day : Time::DayOfWeek = :monday) : Time

  Returns a copy of this `Time` representing the beginning of the week.

- #at_beginning_of_year : Time

  Returns a copy of this `Time` representing the beginning of the year.

- #at_end_of_day : Time

  Returns a copy of this `Time` representing the end of the day.

- #at_end_of_hour : Time

  Returns a copy of this `Time` representing the end of the hour.

- #at_end_of_minute : Time

  Returns a copy of this `Time` representing the end of the minute.

- #at_end_of_month : Time

  Returns a copy of this `Time` representing the end of the month.

- #at_end_of_quarter : Time

  Returns a copy of this `Time` representing the end of the quarter.

- #at_end_of_second : Time

  Returns a copy of this `Time` representing the end of the second.

- #at_end_of_semester : Time

  Returns a copy of this `Time` representing the end of the semester.

- #at_end_of_week : Time

  Returns a copy of this `Time` representing the end of the week.

- #at_end_of_year : Time

  Returns a copy of this `Time` representing the end of the year.

- #at_midday : Time

  Returns a copy of this `Time` representing midday (`12:00`) of the same day.

- #calendar_week : Tuple(Int32, Int32)

  Returns the ISO calendar year and week in which this instance occurs.

- #clone : Time
- #date : Tuple(Int32, Int32, Int32)

  Returns a `Tuple` with `#year`, `#month` and `#day`.

- #day : Int32

  Returns the day of the month (`1..31`).

- #day_of_week : Time::DayOfWeek

  Returns the day of the week (`Monday..Sunday`).

- #day_of_year : Int32

  Returns the day of the year.

- #friday? : Bool

  Returns `true` if the day of week is Friday.

- #hash(hasher)

  See `Object#hash(hasher)`

- #hour : Int32

  Returns the hour of the day (`0..23`).

- #in(location : Location) : Time

  Returns a copy of this `Time` representing the same instant observed in location.

- #inspect(io : IO, with_nanoseconds = true) : Nil

  Prints this `Time` to io.

- #local? : Bool

  Returns `true` if `#location` equals to the local time zone (`Time::Location.local`).

- #location : Location

  Returns `Location` representing the time-zone observed by this `Time`.

- #millisecond : Int32

  Returns the millisecond of the second (`0..999`).

- #minute : Int32

  Returns the minute of the hour (`0..59`).

- #monday? : Bool

  Returns `true` if the day of week is Monday.

- #month : Int32

  Returns the month of the year (`1..12`).

- #nanosecond : Int32

  Returns the nanosecond of the second (`0..999_999_999`).

- #offset : Int32

  Returns the offset from UTC (in seconds) in effect in `#location` at this instant.

- #saturday? : Bool

  Returns `true` if the day of week is Saturday.

- #second : Int32

  Returns the second of the minute (`0..59`).

- #shift(seconds : Int, nanoseconds : Int) : Time

  Returns a copy of this `Time` shifted by the number of seconds and nanoseconds.

- #shift(*, years : Int = 0, months : Int = 0, weeks : Int = 0, days : Int = 0, hours : Int = 0, minutes : Int = 0, seconds : Int = 0, nanoseconds : Int = 0)

  Returns a copy of this `Time` shifted by the amount of calendaric units provided as arguments.

- #sunday? : Bool

  Returns `true` if the day of week is Sunday.

- #thursday? : Bool

  Returns `true` if the day of week is Thursday.

- #time_of_day : Time::Span

  Returns the duration between this `Time` and midnight of the same day.

- #to_json(json : JSON::Builder) : Nil

  Emits a string formatted according to RFC 3339 (ISO 8601 profile).

- #to_local : Time

  Returns a copy of this `Time` representing the same instant in the local time zone (`Time::Location.local`).

- #to_local_in(location : Location) : Time

  Creates a new `Time` instance with the same local date-time representation (wall clock) in a different location.

- #to_rfc2822(io : IO)

  Format this time using the format specified by RFC 2822 into the given io.

- #to_rfc2822 : String

  Format this time using the format specified by RFC 2822.

- #to_rfc3339(io : IO, *, fraction_digits : Int = 0) : Nil

  Format this time using the format specified by RFC 3339 (ISO 8601 profile).

- #to_rfc3339(*, fraction_digits : Int = 0)

  Format this time using the format specified by RFC 3339 (ISO 8601 profile).

- #to_s(io : IO, format : String) : Nil

  Formats this `Time` according to the pattern in format to the given io.

- #to_s(io : IO) : Nil

  Prints this `Time` to io.

- #to_s(format : String) : String

  Formats this `Time` according to the pattern in format.

- #to_unix : Int64

  Returns the number of seconds since the Unix epoch (`1970-01-01 00:00:00Z`).

- #to_unix_f : Float64

  Returns the number of seconds since the Unix epoch (`1970-01-01 00:00:00Z`) as `Float64` with nanosecond precision.

- #to_unix_ms : Int64

  Returns the number of milliseconds since the Unix epoch (`1970-01-01 00:00:00Z`).

- #to_unix_ns : Int128

  Returns the number of nanoseconds since the Unix epoch (`1970-01-01 00:00:00Z`).

- #to_utc : Time

  Returns a copy of this `Time` representing the same instant in UTC (`Time::Location::UTC`).

- #to_yaml(yaml : YAML::Nodes::Builder) : Nil
- #tuesday? : Bool

  Returns `true` if the day of week is Tuesday.

- #utc? : Bool

  Returns `true` if `#location` equals to `Location::UTC`.

- #wednesday? : Bool

  Returns `true` if the day of week is Wednesday.

- #year : Int32

  Returns the year of the proleptic Georgian Calendar (`0..9999`).

- #zone : Time::Location::Zone

  Returns the time zone in effect in `#location` at this instant.

### Instance methods inherited from module `Steppable`

step(*, to limit = nil, by step, exclusive : Bool = false, &) : Nil
step(*, to limit = nil, by step, exclusive : Bool = false) step

### Instance methods inherited from module `Comparable(Time)`

<(other : T) : Bool <, <=(other : T) <=, <=>(other : T) <=>, ==(other : T) ==, >(other : T) : Bool >, >=(other : T) >=, clamp(min, max)
clamp(range : Range) clamp

### Instance methods inherited from struct `Struct`

==(other : YAML::Any)
==(other) : Bool ==, hash(hasher) hash, inspect(io : IO) : Nil inspect, pretty_print(pp) : Nil pretty_print, to_s(io : IO) : Nil to_s

### Class methods inherited from struct `Struct`

pre_initialize(address : Pointer) : Nil pre_initialize

### Instance methods inherited from struct `Value`

==(other : Log::Metadata::Value)
==(other : JSON::Any)
==(other : YAML::Any)
==(other) ==, dup dup

### Instance methods inherited from class `Object`

! : Bool !, !=(other) !=, !~(other) !~, ==(other) ==, ===(other : JSON::Any)
===(other : YAML::Any)
===(other) ===, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash hash, in?(collection : Object) : Bool
in?(*values : Object) : Bool in?, inspect(io : IO) : Nil
inspect : String inspect, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil!(message)
not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO) : Nil
to_json : String to_json, to_pretty_json(indent : String = " ") : String
to_pretty_json(io : IO, indent : String = " ") : Nil to_pretty_json, to_s(io : IO) : Nil
to_s : String to_s, to_yaml(io : IO) : Nil
to_yaml : String to_yaml, try(&) try, unsafe_as(type : T.class) forall T unsafe_as

### Class methods inherited from class `Object`

from_json(string_or_io : String | IO, root : String)
from_json(string_or_io : String | IO) from_json, from_yaml(string_or_io : String | IO) from_yaml

### Macros inherited from class `Object`

class_getter(*names, &block) class_getter, class_getter!(*names) class_getter!, class_getter?(*names, &block) class_getter?, class_property(*names, &block) class_property, class_property!(*names) class_property!, class_property?(*names, &block) class_property?, class_setter(*names) class_setter, def_clone def_clone, def_equals(*fields) def_equals, def_equals_and_hash(*fields) def_equals_and_hash, def_hash(*fields) def_hash, delegate(*methods, to object) delegate, forward_missing_to(delegate) forward_missing_to, getter(*names, &block) getter, getter!(*names) getter!, getter?(*names, &block) getter?, property(*names, &block) property, property!(*names) property!, property?(*names, &block) property?, setter(*names) setter

##
Constructor Detail

def self.local(year : Int32, month : Int32, day : Int32, hour : Int32 = 0, minute : Int32 = 0, second : Int32 = 0, *, nanosecond : Int32 = 0, location : Location = Location.local) : Time #

Creates a new `Time` instance representing the given local date-time in location (defaults to local time zone).

    time = Time.local(2016, 2, 15, 10, 20, 30, location: Time::Location.load("Europe/Berlin"))
    time.inspect # => "2016-02-15 10:20:30+01:00[Europe/Berlin]"

Valid value ranges for the individual fields:

- `#year`: `1..9999`
- `#month`: `1..12`
- `#day`: `1` - `28`/`29`/`30`/`31` (depending on month and year)
- `#hour`: `0..23`
- `#minute`: `0..59`
- `#second`: `0..59`
- `#nanosecond`: `0..999_999_999`

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"

The local date-time representation is resolved to a single instant based on the offset observed in the location at this time.

This process can sometimes be ambiguous, mostly due skipping or repeating times at time zone transitions. For example, in `America/New_York` the date-time `2011-03-13 02:15:00` never occurred, there is a gap between time zones. In return, `2011-11-06 01:15:00` occurred twice because of overlapping time zones.

In such cases, the choice of time zone, and therefore the time, is not well-defined. This method returns a time that is correct in one of the two zones involved in the transition, but it does not guarantee which.

def self.local(location : Location = Location.local) : Time #

Creates a new `Time` instance representing the current time from the system clock observed in location (defaults to local time zone).

def self.month_week_date(year : Int32, month : Int32, week : Int32, day_of_week : Int32 | DayOfWeek, hour : Int32 = 0, minute : Int32 = 0, second : Int32 = 0, *, nanosecond : Int32 = 0, location : Location = Location.local) : self #

Creates an instance representing the week-th day_of_week in the given year and month.

If week is `5` and there are not enough weeks in the given month (e.g. February in a non-leap year), the last week of the month is used instead.

Valid value ranges for the individual fields:

- `#year`: `1..9999`
- `#month`: `1..12`
- `week`: `1..5`
- `#day_of_week`: `0..7`

def self.new(ctx : YAML::ParseContext, node : YAML::Nodes::Node) #
def self.new(pull : JSON::PullParser) : self #

Reads a string from JSON parser as a time formatted according to RFC 3339 or other variations of ISO 8601.

The JSON format itself does not specify a time data type, this method just assumes that a string holding a ISO 8601 time format can be interpreted as a time value.

See `#to_json` for reference.

def self.new(*, seconds : Int64, nanoseconds : Int32, location : Location) #

Creates a new `Time` instance that corresponds to the number of seconds and nanoseconds elapsed from epoch (`0001-01-01 00:00:00.0`) observed in location.

Valid range for seconds is `0..315_537_897_599`. For nanoseconds it is `0..999_999_999`.

def self.parse(time : String, pattern : String, location : Location) : Time #

Parses a `Time` from time string using the given pattern.

See `Time::Format` for details.

    Time.parse("2016-04-05", "%F", Time::Location.load("Europe/Berlin")) # => 2016-04-05 00:00:00+02:00[Europe/Berlin]

If there is no time zone information in the formatted time, location will be assumed. When location is `nil`, in such a case the parser will raise `Time::Format::Error`.

def self.parse!(time : String, pattern : String) : Time #

Parses a `Time` from time string using the given pattern.

See `Time::Format` for details.

    Time.parse!("2016-04-05 +00:00", "%F %:z") # => 2016-04-05 00:00:00.0 +00:00
    Time.parse!("2016-04-05", "%F")            # raises Time::Format::Error

If there is no time zone information in the formatted time, the parser will raise `Time::Format::Error`.

def self.parse_local(time : String, pattern : String) : Time #

Parses a `Time` from time string using the given pattern and `Time::Location.local` as default location

See `Time::Format` for details.

    Time.parse_utc("2016-04-05", "%F") # => 2016-04-05 00:00:00.0 +00:00

`Time::Location.local` will only be used as `#location` if the formatted time does not contain any time zone information. The return value can't be assumed to be a UTC time (this can be achieved by calling `#to_local`).

def self.parse_rfc2822(time : String) : self #

Parse time format specified by RFC 2822.

This is also compatible to RFC 882 and RFC 1123.

    Time.parse_rfc2822("Mon, 15 Feb 2016 04:35:50 UTC") # => 2016-02-15 04:35:50Z

def self.parse_rfc3339(time : String) : self #

Parse time format specified by RFC 3339 (ISO 8601 profile).

    Time.parse_rfc3339("2016-02-15T04:35:50Z") # => 2016-02-15 04:35:50Z

def self.parse_utc(time : String, pattern : String) : Time #

Parses a `Time` from time string using the given pattern and `Time::Location::UTC` as default location.

See `Time::Format` for details.

    Time.parse_utc("2016-04-05", "%F") # => 2016-04-05 00:00:00.0 +00:00

`Time::Location::UTC` will only be used as `#location` if the formatted time does not contain any time zone information. The return value can't be assumed to be a UTC time (this can be achieved by calling `#to_utc`).

def self.unix(seconds : Int) : Time #

Creates a new `Time` instance that corresponds to the number of seconds elapsed since the Unix epoch (`1970-01-01 00:00:00Z`).

The time zone is always UTC.

    Time.unix(981173106) # => 2001-02-03 04:05:06Z

def self.unix_ms(milliseconds : Int) : Time #

Creates a new `Time` instance that corresponds to the number of milliseconds elapsed since the Unix epoch (`1970-01-01 00:00:00Z`).

The time zone is always UTC.

    time = Time.unix_ms(981173106789) # => 2001-02-03 04:05:06.789Z
    time.millisecond                  # => 789

def self.unix_ns(nanoseconds : Int) : Time #

Creates a new `Time` instance that corresponds to the number of nanoseconds elapsed since the Unix epoch (`1970-01-01 00:00:00Z`).

The time zone is always UTC.

    time = Time.unix_ns(981173106789479273) # => 2001-02-03 04:05:06.789479273Z
    time.nanosecond                         # => 789479273

def self.utc(year : Int32, month : Int32, day : Int32, hour : Int32 = 0, minute : Int32 = 0, second : Int32 = 0, *, nanosecond : Int32 = 0) : Time #

Creates a new `Time` instance representing the given date-time in UTC.

    time = Time.utc(2016, 2, 15, 10, 20, 30)
    time.to_s # => "2016-02-15 10:20:30 UTC"

Valid value ranges for the individual fields:

- `#year`: `1..9999`
- `#month`: `1..12`
- `#day`: `1` - `28`/`29`/`30`/`31` (depending on month and year)
- `#hour`: `0..23`
- `#minute`: `0..59`
- `#second`: `0..59`
- `#nanosecond`: `0..999_999_999`

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"

Since UTC does not have any time zone transitions, each date-time is unambiguously resolved.

def self.utc : Time #

Creates a new `Time` instance representing the current time from the system clock in UTC.

def self.utc(*, seconds : Int64, nanoseconds : Int32) : Time #

Creates a new `Time` instance that corresponds to the number of seconds and nanoseconds elapsed from epoch (`0001-01-01 00:00:00Z`) in UTC.

Valid range for seconds is `0..315_537_897_599`. For nanoseconds it is `0..999_999_999`.

def self.week_date(year : Int32, week : Int32, day_of_week : Int32 | DayOfWeek, hour : Int32 = 0, minute : Int32 = 0, second : Int32 = 0, *, nanosecond : Int32 = 0, location : Location = Location.local) : self #

Creates an instance specified by a commercial week date consisting of ISO calendar year, week and a day_of_week.

This equates to the results from `#calendar_week` and `#day_of_week`.

Valid value ranges for the individual fields:

- `#year`: `1..9999`
- `week`: `1..53`
- `#day_of_week`: `1..7`

##
Class Method Detail

def self.days_in_month(year : Int, month : Int) : Int32 #

Returns the number of days in month (value range: `1..12`) taking account of the year.

The returned value is either `28`, `29`, `30` or `31` depending on the month and whether year is leap.

    Time.days_in_month(2016, 2) # => 29
    Time.days_in_month(1990, 4) # => 30

def self.days_in_year(year : Int) : Int32 #

Returns the number of days in year.

A normal year has `365` days, a leap year `366` days.

    Time.days_in_year(1990) # => 365
    Time.days_in_year(2004) # => 366

def self.leap_year?(year : Int) : Bool #

Returns `true` if year is a leap year in the proleptic Gregorian calendar.

def self.measure(&) : Time::Span #

Measures the execution time of block.

The measurement relies on the monotonic clock and is not affected by fluctuations of the system clock (see `#monotonic`).

    elapsed_time = Time.measure do
      # operation that takes 20 milliseconds
    end
    elapsed_time # => 20.milliseconds (approximately)

def self.monotonic : Time::Span #

Returns a reading from the monotonic clock to measure elapsed time.

Values from the monotonic clock and wall clock are not comparable. This method does not return a `Time` instance but a `Time::Span` amounting to the number of nanoseconds elapsed since the unspecified starting point of the monotonic clock. The returned values are strictly linearly increasing.

This clock should be independent from discontinuous jumps in the system time, such as leap seconds, time zone adjustments or manual changes to the computer's clock.

Subtracting two results from this method equals to the time elapsed between both readings:

    start = Time.monotonic
    # operation that takes 20 milliseconds
    elapsed = Time.monotonic - start # => 20.milliseconds (approximately)
    # operation that takes 50 milliseconds
    elapsed_total = Time.monotonic - start # => 70.milliseconds (approximately)

The execution time of a block can be measured using `.measure`.

def self.parse_iso8601(time : String) #

Parse datetime format specified by ISO 8601.

This is similar to `.parse_rfc3339` but RFC 3339 defines a more strict format. In ISO 8601 for examples, field delimiters (`#-`, `:`) are optional.

Use `#to_rfc3339` to format a `Time` according to .

    Time.parse_iso8601("2016-02-15T04:35:50Z") # => 2016-02-15 04:35:50Z

##
Instance Method Detail

def +(span : Time::Span) : Time #

Returns a copy of this `Time` with span added.

See `#shift` for details.

def +(span : Time::MonthSpan) : Time #

Returns a copy of this `Time` with span added.

It adds the number of months with overflow increasing the year. If the resulting day-of-month would be invalid, it is adjusted to the last valid day of the month.

For example, adding `1.month` to `2007-03-31` would result in the invalid date `2007-04-31` which will be adjusted to `2007-04-30`.

This operates on the local time-line, such that the local date-time representations of month and year are increased by the specified amount.

If the resulting date-time is ambiguous due to time zone transitions, a correct time will be returned, but it does not guarantee which.

def -(other : Time) : Time::Span #

Returns a `Time::Span` amounting to the duration between other and `self`.

The time span is negative if `self` is before other.

The duration amounts to the actual time elapsed between both instances, on the instant time-line. The difference between local date-time representations may equal to a different duration, depending on time zone transitions.

def -(span : Time::Span) : Time #

Returns a copy of this `Time` with span subtracted.

See `#shift` for details.

def -(span : Time::MonthSpan) : Time #

Returns a copy of this `Time` with span subtracted.

It adds the number of months with overflow decreasing the year. If the resulting day-of-month would be invalid, it is adjusted to the last valid day of the month.

For example, subtracting `1.month` from `2007-05-31` would result in the invalid date `2007-04-31` which will be adjusted to `2007-04-30`.

This operates on the local time-line, such that the local date-time representations of month and year are decreased by the specified amount.

If the resulting date-time is ambiguous due to time zone transitions, a correct time will be returned, but it does not guarantee which.

def <=>(other : Time) : Int32 #

Compares this `Time` with other.

The comparison is based on the instant time-line, even if the local date-time representation (wall clock) would compare differently.

To ensure the comparison is also true for local wall clock, both date-times need to be transformed to the same time zone.

def ==(other : Time) : Bool #

Compares this `Time` with other for equality.

Two instances are considered equal if they represent the same date-time in the instant time-line, even if they show a different local date-time.

    time_de = Time.local(2018, 3, 8, 22, 5, 13, location: Time::Location.load("Europe/Berlin"))
    time_ar = Time.local(2018, 3, 8, 18, 5, 13, location: Time::Location.load("America/Argentina/Buenos_Aires"))
    time_de == time_ar # => true

    # both times represent the same instant:
    time_de.to_utc # => 2018-03-08 21:05:13Z
    time_ar.to_utc # => 2018-03-08 21:05:13Z

def at_beginning_of_day : Time #

Returns a copy of this `Time` representing the beginning of the day.

def at_beginning_of_hour : Time #

Returns a copy of this `Time` representing the beginning of the hour.

def at_beginning_of_minute : Time #

Returns a copy of this `Time` representing the beginning of the minute.

def at_beginning_of_month : Time #

Returns a copy of this `Time` representing the beginning of the month.

def at_beginning_of_quarter : Time #

Returns a copy of this `Time` representing the beginning of the quarter.

def at_beginning_of_second : Time #

Returns a copy of this `Time` representing the beginning of the seconds.

This essentially resets `nanoseconds` to 0.

def at_beginning_of_semester : Time #

Returns a copy of this `Time` representing the beginning of the semester.

def at_beginning_of_week(start_day : Time::DayOfWeek = :monday) : Time #

Returns a copy of this `Time` representing the beginning of the week.

The week starts on Monday by default, but can be configured by passing a different `start_day` as a `Time::DayOfWeek`.

    now = Time.utc(2023, 5, 16, 17, 53, 22)
    now.at_beginning_of_week             # => 2023-05-15 00:00:00Z
    now.at_beginning_of_week(:sunday)    # => 2023-05-14 00:00:00Z
    now.at_beginning_of_week(:wednesday) # => 2023-05-10 00:00:00Z

def at_beginning_of_year : Time #

Returns a copy of this `Time` representing the beginning of the year.

def at_end_of_day : Time #

Returns a copy of this `Time` representing the end of the day.

def at_end_of_hour : Time #

Returns a copy of this `Time` representing the end of the hour.

def at_end_of_minute : Time #

Returns a copy of this `Time` representing the end of the minute.

def at_end_of_month : Time #

Returns a copy of this `Time` representing the end of the month.

def at_end_of_quarter : Time #

Returns a copy of this `Time` representing the end of the quarter.

def at_end_of_second : Time #

Returns a copy of this `Time` representing the end of the second.

def at_end_of_semester : Time #

Returns a copy of this `Time` representing the end of the semester.

def at_end_of_week : Time #

Returns a copy of this `Time` representing the end of the week.

def at_end_of_year : Time #

Returns a copy of this `Time` representing the end of the year.

def at_midday : Time #

Returns a copy of this `Time` representing midday (`12:00`) of the same day.

def calendar_week : Tuple(Int32, Int32) #

Returns the ISO calendar year and week in which this instance occurs.

The ISO calendar year to which the week belongs is not always in the same as the year of the regular calendar date. The first three days of January sometimes belong to week 52 (or 53) of the previous year; equally the last three days of December sometimes are already in week 1 of the following year.

For that reason, this method returns a tuple `year, week` consisting of the calendar year to which the calendar week belongs and the ordinal number of the week within that year.

Together with `#day_of_week` this represents a specific day as commercial or week date format `year, week, day_of_week` in the same way as the typical format `year, month, day`. `.week_date` creates a `Time` instance from a week date.

def clone : Time #
def date : Tuple(Int32, Int32, Int32) #

Returns a `Tuple` with `#year`, `#month` and `#day`.

def day : Int32 #

Returns the day of the month (`1..31`).

def day_of_week : Time::DayOfWeek #

Returns the day of the week (`Monday..Sunday`).

def day_of_year : Int32 #

Returns the day of the year.

The value range is `1..365` in normal years and `1..366` in leap years.

def friday? : Bool #

Returns `true` if the day of week is Friday.

See `#day_of_week` for details.

def hash(hasher) #
Description copied from struct Struct

See `Object#hash(hasher)`

def hour : Int32 #

Returns the hour of the day (`0..23`).

def in(location : Location) : Time #

Returns a copy of this `Time` representing the same instant observed in location.

This method changes the time zone and retains the instant, which will usually result in a different representation of local date-time (unless both locations have the same offset).

Ambiguous time zone transitions such as gaps and overlaps have no effect on the result because it retains the same instant.

    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/Argentina/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/Argentina/Buenos_Aires]

In contrast, `#to_local_in` changes to a different location while preserving the same wall time, which results in different instants on the time line.

def inspect(io : IO, with_nanoseconds = true) : Nil #

Prints this `Time` to io.

It's formatted according to the Internet Extended Date/Time Format (IXDTF) as specified in RFC 9557: An RFC 3339 formatted local date-time string with nanosecond precision followed by a time zone name suffix.

It is similar to the format `%FT%T.%N%::z[%Z]`. Some parts may be omitted or shortened.

Nanoseconds are omitted if with_nanoseconds is `false` or `nanoseconds` are zero. Zero offset seconds are omitted. The name of the location is omitted for fixed zone offset.

    Time.utc(2014, 1, 2, 3, 4, 5)                      # => 2014-01-02 03:04:05Z
    Time.utc(2014, 1, 2, 3, 4, 5, nanosecond: 123_456) # => 2014-01-02 03:04:05.123456000Z

    Time.local(2014, 1, 2, 3, 4, 5, location: Time::Location.load("Europe/Berlin")) # => 2014-01-02 03:04:05+01:00[Europe/Berlin]
    Time.local(2014, 1, 2, 3, 4, 5, location: Time::Location.fixed(3600))           # => 2014-01-02 03:04:05+01:00
    Time.local(2014, 1, 2, 3, 4, 5, location: Time::Location.fixed(3601))           # => 2014-01-02 03:04:05+01:00:01

def local? : Bool #

Returns `true` if `#location` equals to the local time zone (`Time::Location.local`).

Since the system's settings may change during a program's runtime, the result may not be identical between different invocations.

def location : Location #

Returns `Location` representing the time-zone observed by this `Time`.

def millisecond : Int32 #

Returns the millisecond of the second (`0..999`).

def minute : Int32 #

Returns the minute of the hour (`0..59`).

def monday? : Bool #

Returns `true` if the day of week is Monday.

See `#day_of_week` for details.

def month : Int32 #

Returns the month of the year (`1..12`).

def nanosecond : Int32 #

Returns the nanosecond of the second (`0..999_999_999`).

def offset : Int32 #

Returns the offset from UTC (in seconds) in effect in `#location` at this instant.

def saturday? : Bool #

Returns `true` if the day of week is Saturday.

See `#day_of_week` for details.

def second : Int32 #

Returns the second of the minute (`0..59`).

def shift(seconds : Int, nanoseconds : Int) : Time #

Returns a copy of this `Time` shifted by the number of seconds and nanoseconds.

Positive values result in a later time, negative values in an earlier time.

This operates on the instant time-line, such that adding the equivalent of one hour will always be a duration of one hour later. The local date-time representation may change by a different amount, depending on time zone transitions.

Overflow in nanoseconds will be transferred to seconds.

There is no explicit limit on the input values but the addition must result in a valid time between `0001-01-01 00:00:00.0` and `9999-12-31 23:59:59.999_999_999`. Otherwise `ArgumentError` is raised.

def shift(*, years : Int = 0, months : Int = 0, weeks : Int = 0, days : Int = 0, hours : Int = 0, minutes : Int = 0, seconds : Int = 0, nanoseconds : Int = 0) #

Returns a copy of this `Time` shifted by the amount of calendaric units provided as arguments.

Positive values result in a later time, negative values in an earlier time.

This operates on the local time-line, such that the local date-time representation of the result will be apart by the specified amounts, but the elapsed time between both instances might not equal to the combined default duration. This is the case for example when adding a day over a daylight-savings time change:

    start = Time.local(2017, 10, 28, 13, 37, location: Time::Location.load("Europe/Berlin"))
    one_day_later = start.shift days: 1

    one_day_later - start # => 25.hours

years is equivalent to `12` months and weeks is equivalent to `7` days.

If the day-of-month resulting from shifting by years and months would be invalid, the date is adjusted to the last valid day of the month. For example, adding one month to `2018-08-31` would result in the invalid date `2018-09-31` which will be adjusted to `2018-09-30`:

    Time.utc(2018, 7, 31).shift(months: 1) # => Time.utc(2018, 8, 31)
    Time.utc(2018, 8, 31).shift(months: 1) # => Time.utc(2018, 9, 30)

Overflow in smaller units is transferred to the next larger unit.

Changes are applied in the same order as the arguments, sorted by increasing granularity. This is relevant because the order of operations can change the result:

    Time.utc(2018, 8, 31).shift(months: 1, days: -1)       # => Time.utc(2018, 9, 29)
    Time.utc(2018, 8, 31).shift(months: 1).shift(days: -1) # => Time.utc(2018, 9, 29)
    Time.utc(2018, 8, 31).shift(days: -1).shift(months: 1) # => Time.utc(2018, 9, 30)

There is no explicit limit on the input values but the shift must result in a valid time between `0001-01-01 00:00:00.0` and `9999-12-31 23:59:59.999_999_999`. Otherwise `ArgumentError` is raised.

If the resulting date-time is ambiguous due to time zone transitions, a correct time will be returned, but it does not guarantee which.

def sunday? : Bool #

Returns `true` if the day of week is Sunday.

See `#day_of_week` for details.

def thursday? : Bool #

Returns `true` if the day of week is Thursday.

See `#day_of_week` for details.

def time_of_day : Time::Span #

Returns the duration between this `Time` and midnight of the same day.

This is equivalent to creating a `Time::Span` from the time-of-day fields:

    time.time_of_day == Time::Span.new(hours: time.hour, minutes: time.minute, seconds: time.second, nanoseconds: time.nanosecond)

def to_json(json : JSON::Builder) : Nil #

Emits a string formatted according to RFC 3339 (ISO 8601 profile).

The JSON format itself does not specify a time data type, this method just assumes that a string holding a RFC 3339 time format will be interpreted as a time value.

See `#from_json` for reference.

def to_local : Time #

Returns a copy of this `Time` representing the same instant in the local time zone (`Time::Location.local`).

See `#in` for details.

def to_local_in(location : Location) : Time #

Creates a new `Time` instance with the same local date-time representation (wall clock) in a different location.

Unlike `#in`, which always preserves the same instant in time, `#to_local_in` adjusts the instant such that it results in the same local date-time representation. Both instants are apart from each other by the difference in zone offsets.

    new_year = Time.utc(2019, 1, 1, 0, 0, 0)
    tokyo = new_year.to_local_in(Time::Location.load("Asia/Tokyo"))
    new_york = new_year.to_local_in(Time::Location.load("America/New_York"))
    tokyo.inspect    # => "2019-01-01 00:00:00+09:00[Asia/Tokyo]"
    new_york.inspect # => "2019-01-01 00:00:00-05:00[America/New_York]"

If the given wall clock is a gap or fold in the target location, no unambiguous equivalent representation exists.

- In case of a gap, the clock jumps to the smaller offset and shows a time before the gap. The wall clock is different from `self`.
- In case of a fold, the clock chooses the bigger offset and shows a time after the fold. The wall clock is identical to `self`.

    nyc = Time::Location.load("America/New_York")

    # gap on 2025-03-09 local time: 02:00:00 STD -> 03:00:00 DST
    Time.utc(2025, 3, 9, 2, 12, 34).to_local_in(nyc) # => 2025-03-09 01:12:34.0-05:00[America/New_York]

    # overlap on 2025-11-02 local time: 02:00:00 DST -> 01:00:00 STD
    Time.utc(2025, 11, 2, 1, 12, 34).to_local_in(nyc) # => 2025-11-02 01:12:34.0-04:00[America/New_York]

def to_rfc2822(io : IO) #

Format this time using the format specified by RFC 2822 into the given io.

This is also compatible to RFC 882 and RFC 1123.

def to_rfc2822 : String #

Format this time using the format specified by RFC 2822.

    Time.utc(2016, 2, 15).to_rfc2822 # => "Mon, 15 Feb 2016 00:00:00 +0000"

This is also compatible to RFC 882 and RFC 1123.

def to_rfc3339(io : IO, *, fraction_digits : Int = 0) : Nil #

Format this time using the format specified by RFC 3339 (ISO 8601 profile). into the given io.

Number of seconds decimals can be selected with fraction_digits. Values accepted are 0 (the default, no decimals), 3 (milliseconds), 6 (microseconds) or 9 (nanoseconds).

def to_rfc3339(*, fraction_digits : Int = 0) #

Format this time using the format specified by RFC 3339 (ISO 8601 profile).

    Time.utc(2016, 2, 15).to_rfc3339 # => "2016-02-15 00:00:00Z"

ISO 8601 allows some freedom over the syntax and RFC 3339 exercises that freedom to rigidly define a fixed format intended for use in internet protocols and standards.

Number of seconds decimals can be selected with fraction_digits. Values accepted are 0 (the default, no decimals), 3 (milliseconds), 6 (microseconds) or 9 (nanoseconds).

def to_s(io : IO, format : String) : Nil #

Formats this `Time` according to the pattern in format to the given io.

See `Time::Format` for details.

def to_s(io : IO) : Nil #

Prints this `Time` to io.

The local date-time is formatted as date string `YYYY-MM-DD HH:mm:ss +ZZ:ZZ:ZZ`. Nanoseconds are always omitted. When the location is `UTC`, the offset is replaced with the string `UTC`. Offset seconds are omitted if `0`.

def to_s(format : String) : String #

Formats this `Time` according to the pattern in format.

See `Time::Format` for details.

    time = Time.local(2016, 4, 5)
    time.to_s("%F") # => "2016-04-05"

def to_unix : Int64 #

Returns the number of seconds since the Unix epoch (`1970-01-01 00:00:00Z`).

    time = Time.utc(2016, 1, 12, 3, 4, 5)
    time.to_unix # => 1452567845

def to_unix_f : Float64 #

Returns the number of seconds since the Unix epoch (`1970-01-01 00:00:00Z`) as `Float64` with nanosecond precision.

    time = Time.utc(2016, 1, 12, 3, 4, 5, nanosecond: 678_000_000)
    time.to_unix_f # => 1452567845.678

def to_unix_ms : Int64 #

Returns the number of milliseconds since the Unix epoch (`1970-01-01 00:00:00Z`).

    time = Time.utc(2016, 1, 12, 3, 4, 5, nanosecond: 678_000_000)
    time.to_unix_ms # => 1452567845678

def to_unix_ns : Int128 #

Returns the number of nanoseconds since the Unix epoch (`1970-01-01 00:00:00Z`).

    time = Time.utc(2016, 1, 12, 3, 4, 5, nanosecond: 678_910_123)
    time.to_unix_ns # => 1452567845678910123

def to_utc : Time #

Returns a copy of this `Time` representing the same instant in UTC (`Time::Location::UTC`).

See `#in` for details.

def to_yaml(yaml : YAML::Nodes::Builder) : Nil #
def tuesday? : Bool #

Returns `true` if the day of week is Tuesday.

See `#day_of_week` for details.

def utc? : Bool #

Returns `true` if `#location` equals to `Location::UTC`.

def wednesday? : Bool #

Returns `true` if the day of week is Wednesday.

See `#day_of_week` for details.

def year : Int32 #

Returns the year of the proleptic Georgian Calendar (`0..9999`).

def zone : Time::Location::Zone #

Returns the time zone in effect in `#location` at this instant.