class TZInfo::Timestamp
A time represented as an ‘Integer` number of seconds since 1970-01-01 00:00:00 UTC (ignoring leap seconds and using the proleptic Gregorian calendar), the fraction through the second (sub_second
as a `Rational`) and an optional UTC offset. Like Ruby’s ‘Time` class, {Timestamp} can distinguish between a local time with a zero offset and a time specified explicitly as UTC.
Attributes
@return [Numeric] the fraction of a second elapsed since timestamp as
either a `Rational` or the `Integer` 0. Always greater than or equal to 0 and less than 1.
@return [Integer] the offset from UTC in seconds or ‘nil` if the
{Timestamp} doesn't have a specified offset.
@return [Integer] the number of seconds since 1970-01-01 00:00:00 UTC
ignoring leap seconds (i.e. each day is treated as if it were 86,400 seconds long).
Public Class Methods
Returns a new {Timestamp} representing the (proleptic Gregorian calendar) date and time specified by the supplied parameters.
If ‘utc_offset` is `nil`, `:utc` or 0, the date and time parameters will be interpreted as representing a UTC date and time. Otherwise the date and time parameters will be interpreted as a local date and time with the given offset.
@param year [Integer] the year. @param month [Integer] the month (1-12). @param day [Integer] the day of the month (1-31). @param hour [Integer] the hour (0-23). @param minute [Integer] the minute (0-59). @param second [Integer] the second (0-59). @param sub_second
[Numeric] the fractional part of the second as either
a `Rational` that is greater than or equal to 0 and less than 1, or the `Integer` 0.
@param utc_offset
[Object] either ‘nil` for a {Timestamp} without a
specified offset, an offset from UTC specified as an `Integer` number of seconds or the `Symbol` `:utc`).
@return [Timestamp] a new {Timestamp} representing the specified
(proleptic Gregorian calendar) date and time.
@raise [ArgumentError] if either of ‘year`, `month`, `day`, `hour`,
`minute`, or `second` is not an `Integer`.
@raise [ArgumentError] if ‘sub_second` is not a `Rational`, or the
`Integer` 0.
@raise [ArgumentError] if ‘utc_offset` is not `nil`, not an `Integer`
and not the `Symbol` `:utc`.
@raise [RangeError] if ‘month` is not between 1 and 12. @raise [RangeError] if `day` is not between 1 and 31. @raise [RangeError] if `hour` is not between 0 and 23. @raise [RangeError] if `minute` is not between 0 and 59. @raise [RangeError] if `second` is not between 0 and 59. @raise [RangeError] if `sub_second` is a `Rational` but that is less
than 0 or greater than or equal to 1.
# File lib/tzinfo/timestamp.rb, line 55 def create(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, sub_second = 0, utc_offset = nil) raise ArgumentError, 'year must be an Integer' unless year.kind_of?(Integer) raise ArgumentError, 'month must be an Integer' unless month.kind_of?(Integer) raise ArgumentError, 'day must be an Integer' unless day.kind_of?(Integer) raise ArgumentError, 'hour must be an Integer' unless hour.kind_of?(Integer) raise ArgumentError, 'minute must be an Integer' unless minute.kind_of?(Integer) raise ArgumentError, 'second must be an Integer' unless second.kind_of?(Integer) raise RangeError, 'month must be between 1 and 12' if month < 1 || month > 12 raise RangeError, 'day must be between 1 and 31' if day < 1 || day > 31 raise RangeError, 'hour must be between 0 and 23' if hour < 0 || hour > 23 raise RangeError, 'minute must be between 0 and 59' if minute < 0 || minute > 59 raise RangeError, 'second must be between 0 and 59' if second < 0 || second > 59 # Based on days_from_civil from https://howardhinnant.github.io/date_algorithms.html#days_from_civil after_february = month > 2 year -= 1 unless after_february era = year / 400 year_of_era = year - era * 400 day_of_year = (153 * (month + (after_february ? -3 : 9)) + 2) / 5 + day - 1 day_of_era = year_of_era * 365 + year_of_era / 4 - year_of_era / 100 + day_of_year days_since_epoch = era * 146097 + day_of_era - 719468 value = ((days_since_epoch * 24 + hour) * 60 + minute) * 60 + second value -= utc_offset if utc_offset.kind_of?(Integer) new(value, sub_second, utc_offset) end
When used without a block, returns a {Timestamp} representation of a given ‘Time`, `DateTime` or {Timestamp}.
When called with a block, the {Timestamp} representation of ‘value` is passed to the block. The block must then return a {Timestamp}, which will be converted back to the type of the initial value. If the initial value was a {Timestamp}, the block result will be returned. If the initial value was a `DateTime`, a Gregorian `DateTime` will be returned.
The UTC offset of ‘value` can either be preserved (the {Timestamp} representation will have the same UTC offset as `value`), ignored (the {Timestamp} representation will have no defined UTC offset), or treated as though it were UTC (the {Timestamp} representation will have a {utc_offset} of 0 and {utc?} will return `true`).
@param value [Object] a ‘Time`, `DateTime` or {Timestamp}. @param offset [Symbol] either `:preserve` to preserve the offset of
`value`, `:ignore` to ignore the offset of `value` and create a {Timestamp} with an unspecified offset, or `:treat_as_utc` to treat the offset of `value` as though it were UTC and create a UTC {Timestamp}.
@yield [timestamp] if a block is provided, the {Timestamp}
representation is passed to the block.
@yieldparam timestamp [Timestamp] the {Timestamp} representation of
`value`.
@yieldreturn [Timestamp] a {Timestamp} to be converted back to the type
of `value`.
@return [Object] if called without a block, the {Timestamp}
representation of `value`, otherwise the result of the block, converted back to the type of `value`.
# File lib/tzinfo/timestamp.rb, line 112 def for(value, offset = :preserve) raise ArgumentError, 'value must be specified' unless value case offset when :ignore ignore_offset = true target_utc_offset = nil when :treat_as_utc ignore_offset = true target_utc_offset = :utc when :preserve ignore_offset = false target_utc_offset = nil else raise ArgumentError, 'offset must be :preserve, :ignore or :treat_as_utc' end time_like = false timestamp = case value when Time for_time(value, ignore_offset, target_utc_offset) when DateTime for_datetime(value, ignore_offset, target_utc_offset) when Timestamp for_timestamp(value, ignore_offset, target_utc_offset) else raise ArgumentError, "#{value.class} values are not supported" unless is_time_like?(value) time_like = true for_time_like(value, ignore_offset, target_utc_offset) end if block_given? result = yield timestamp raise ArgumentError, 'block must return a Timestamp' unless result.kind_of?(Timestamp) case value when Time result.to_time when DateTime result.to_datetime else # A Time-like value or a Timestamp time_like ? result.to_time : result end else timestamp end end
Initializes a new {Timestamp}.
@param value [Integer] the number of seconds since 1970-01-01 00:00:00 UTC
ignoring leap seconds.
@param sub_second
[Numeric] the fractional part of the second as either a
`Rational` that is greater than or equal to 0 and less than 1, or the `Integer` 0.
@param utc_offset
[Object] either ‘nil` for a {Timestamp} without a
specified offset, an offset from UTC specified as an `Integer` number of seconds or the `Symbol` `:utc`).
@raise [ArgumentError] if ‘value` is not an `Integer`. @raise [ArgumentError] if `sub_second` is not a `Rational`, or the
`Integer` 0.
@raise [RangeError] if ‘sub_second` is a `Rational` but that is less
than 0 or greater than or equal to 1.
@raise [ArgumentError] if ‘utc_offset` is not `nil`, not an `Integer` and
not the `Symbol` `:utc`.
# File lib/tzinfo/timestamp.rb, line 344 def initialize(value, sub_second = 0, utc_offset = nil) raise ArgumentError, 'value must be an Integer' unless value.kind_of?(Integer) raise ArgumentError, 'sub_second must be a Rational or the Integer 0' unless (sub_second.kind_of?(Integer) && sub_second == 0) || sub_second.kind_of?(Rational) raise RangeError, 'sub_second must be >= 0 and < 1' if sub_second < 0 || sub_second >= 1 raise ArgumentError, 'utc_offset must be an Integer, :utc or nil' if utc_offset && utc_offset != :utc && !utc_offset.kind_of?(Integer) initialize!(value, sub_second, utc_offset) end
Creates a new UTC {Timestamp}.
@param value [Integer] the number of seconds since 1970-01-01 00:00:00
UTC ignoring leap seconds.
@param sub_second
[Numeric] the fractional part of the second as either
a `Rational` that is greater than or equal to 0 and less than 1, or the `Integer` 0.
@raise [ArgumentError] if ‘value` is not an `Integer`. @raise [ArgumentError] if `sub_second` is not a `Rational`, or the
`Integer` 0.
@raise [RangeError] if ‘sub_second` is a `Rational` but that is less
than 0 or greater than or equal to 1.
# File lib/tzinfo/timestamp.rb, line 172 def utc(value, sub_second = 0) new(value, sub_second, :utc) end
Public Instance Methods
Compares this {Timestamp} with another.
{Timestamp} instances without a defined UTC offset are not comparable with {Timestamp} instances that have a defined UTC offset.
@param t [Timestamp] the {Timestamp} to compare this instance with. @return [Integer] -1, 0 or 1 depending if this instance is earlier, equal
or later than `t` respectively. Returns `nil` when comparing a {Timestamp} that does not have a defined UTC offset with a {Timestamp} that does have a defined UTC offset. Returns `nil` if `t` is not a {Timestamp}.
# File lib/tzinfo/timestamp.rb, line 454 def <=>(t) return nil unless t.kind_of?(Timestamp) return nil if utc_offset && !t.utc_offset return nil if !utc_offset && t.utc_offset result = value <=> t.value result = sub_second <=> t.sub_second if result == 0 result end
Adds a number of seconds to the {Timestamp} value, setting the UTC offset of the result.
@param seconds [Integer] the number of seconds to be added. @param utc_offset
[Object] either ‘nil` for a {Timestamp} without a
specified offset, an offset from UTC specified as an `Integer` number of seconds or the `Symbol` `:utc`).
@return [Timestamp] the result of adding ‘seconds` to the
{Timestamp} value as a new {Timestamp} instance with the chosen `utc_offset`.
@raise [ArgumentError] if ‘seconds` is not an `Integer`. @raise [ArgumentError] if `utc_offset` is not `nil`, not an `Integer` and
not the `Symbol` `:utc`.
# File lib/tzinfo/timestamp.rb, line 372 def add_and_set_utc_offset(seconds, utc_offset) raise ArgumentError, 'seconds must be an Integer' unless seconds.kind_of?(Integer) raise ArgumentError, 'utc_offset must be an Integer, :utc or nil' if utc_offset && utc_offset != :utc && !utc_offset.kind_of?(Integer) return self if seconds == 0 && utc_offset == (@utc ? :utc : @utc_offset) Timestamp.send(:new!, @value + seconds, @sub_second, utc_offset) end
@return [Integer] a hash based on the value, sub-second and whether there
is a defined UTC offset.
# File lib/tzinfo/timestamp.rb, line 468 def hash [@value, @sub_second, !!@utc_offset].hash end
@return [String] the internal object state as a programmer-readable
`String`.
# File lib/tzinfo/timestamp.rb, line 474 def inspect "#<#{self.class}: @value=#{@value}, @sub_second=#{@sub_second}, @utc_offset=#{@utc_offset.inspect}, @utc=#{@utc.inspect}>" end
Formats this {Timestamp} according to the directives in the given format string.
@param format [String] the format string. Please refer to ‘Time#strftime`
for a list of supported format directives.
@return [String] the formatted {Timestamp}. @raise [ArgumentError] if ‘format` is not specified.
# File lib/tzinfo/timestamp.rb, line 426 def strftime(format) raise ArgumentError, 'format must be specified' unless format to_time.strftime(format) end
Converts this {Timestamp} to a Gregorian ‘DateTime`.
@return [DateTime] a Gregorian ‘DateTime` representation of this
{Timestamp}. If the UTC offset of this {Timestamp} is not specified, a UTC `DateTime` will be returned.
# File lib/tzinfo/timestamp.rb, line 406 def to_datetime new_datetime end
Converts this {Timestamp} to an ‘Integer` number of seconds since 1970-01-01 00:00:00 UTC (ignoring leap seconds).
@return [Integer] an ‘Integer` representation of this {Timestamp} (the
number of seconds since 1970-01-01 00:00:00 UTC ignoring leap seconds).
# File lib/tzinfo/timestamp.rb, line 415 def to_i value end
@return [String] a ‘String` representation of this {Timestamp}.
# File lib/tzinfo/timestamp.rb, line 432 def to_s return value_and_sub_second_to_s unless @utc_offset return "#{value_and_sub_second_to_s} UTC" if @utc sign = @utc_offset >= 0 ? '+' : '-' min, sec = @utc_offset.abs.divmod(60) hour, min = min.divmod(60) "#{value_and_sub_second_to_s(@utc_offset)} #{sign}#{'%02d' % hour}:#{'%02d' % min}#{sec > 0 ? ':%02d' % sec : nil}#{@utc_offset != 0 ? " (#{value_and_sub_second_to_s} UTC)" : nil}" end
Converts this {Timestamp} to a ‘Time`.
@return [Time] a ‘Time` representation of this {Timestamp}. If the UTC
offset of this {Timestamp} is not specified, a UTC `Time` will be returned.
# File lib/tzinfo/timestamp.rb, line 391 def to_time time = new_time if @utc_offset && !@utc time.localtime(@utc_offset) else time.utc end end
@return [Timestamp] a UTC {Timestamp} equivalent to this instance. Returns
`self` if {#utc? self.utc?} is `true`.
# File lib/tzinfo/timestamp.rb, line 381 def utc return self if @utc Timestamp.send(:new!, @value, @sub_second, :utc) end
@return [Boolean] ‘true` if this {Timestamp} represents UTC, `false` if
the {Timestamp} wasn't specified as UTC or `nil` if the {Timestamp} has no specified offset.
# File lib/tzinfo/timestamp.rb, line 355 def utc? @utc end
Protected Instance Methods
Constructs a new instance of a ‘DateTime` or `DateTime`-like class with the same {value}, {sub_second} and {utc_offset} as this {Timestamp}.
@param klass [Class] the class to instantiate.
@private
# File lib/tzinfo/timestamp.rb, line 496 def new_datetime(klass = DateTime) # Can't specify the start parameter unless the jd parameter is an exact number of days. # Use #gregorian instead. datetime = klass.jd(JD_EPOCH + ((@value.to_r + @sub_second) / 86400)).gregorian @utc_offset && @utc_offset != 0 ? datetime.new_offset(Rational(@utc_offset, 86400)) : datetime end
Creates a new instance of a ‘Time` or `Time`-like class matching the {value} and {sub_second} of this {Timestamp}, but not setting the offset.
@param klass [Class] the class to instantiate.
@private
# File lib/tzinfo/timestamp.rb, line 486 def new_time(klass = Time) klass.at(@value, @sub_second * 1_000_000) end