Class: TZInfo::Timestamp

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/tzinfo/timestamp.rb

Overview

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.

Direct Known Subclasses

TimestampWithOffset

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value, sub_second = 0, utc_offset = nil) ⇒ Timestamp

Initializes a new TZInfo::Timestamp.

Parameters:

  • value (Integer)

    the number of seconds since 1970-01-01 00:00:00 UTC ignoring leap seconds.

  • sub_second (Numeric) (defaults to: 0)

    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.

  • utc_offset (Object) (defaults to: nil)

    either nil for a TZInfo::Timestamp without a specified offset, an offset from UTC specified as an Integer number of seconds or the Symbol :utc).

Raises:

  • (ArgumentError)

    if value is not an Integer.

  • (ArgumentError)

    if sub_second is not a Rational, or the Integer 0.

  • (RangeError)

    if sub_second is a Rational but that is less than 0 or greater than or equal to 1.

  • (ArgumentError)

    if utc_offset is not nil, not an Integer and not the Symbol :utc.


344
345
346
347
348
349
350
# 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

Instance Attribute Details

#sub_secondNumeric (readonly)

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

Returns:

  • (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.


321
322
323
# File 'lib/tzinfo/timestamp.rb', line 321

def sub_second
  @sub_second
end

#utc_offsetInteger (readonly)

Returns the offset from UTC in seconds or nil if the TZInfo::Timestamp doesn't have a specified offset.

Returns:

  • (Integer)

    the offset from UTC in seconds or nil if the TZInfo::Timestamp doesn't have a specified offset.


325
326
327
# File 'lib/tzinfo/timestamp.rb', line 325

def utc_offset
  @utc_offset
end

#valueInteger (readonly)

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

Returns:

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


316
317
318
# File 'lib/tzinfo/timestamp.rb', line 316

def value
  @value
end

Class Method Details

.create(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, sub_second = 0, utc_offset = nil) ⇒ Timestamp

Returns a new TZInfo::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.

Parameters:

  • year (Integer)

    the year.

  • month (Integer) (defaults to: 1)

    the month (1-12).

  • day (Integer) (defaults to: 1)

    the day of the month (1-31).

  • hour (Integer) (defaults to: 0)

    the hour (0-23).

  • minute (Integer) (defaults to: 0)

    the minute (0-59).

  • second (Integer) (defaults to: 0)

    the second (0-59).

  • sub_second (Numeric) (defaults to: 0)

    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.

  • utc_offset (Object) (defaults to: nil)

    either nil for a TZInfo::Timestamp without a specified offset, an offset from UTC specified as an Integer number of seconds or the Symbol :utc).

Returns:

Raises:

  • (ArgumentError)

    if either of year, month, day, hour, minute, or second is not an Integer.

  • (ArgumentError)

    if sub_second is not a Rational, or the Integer 0.

  • (ArgumentError)

    if utc_offset is not nil, not an Integer and not the Symbol :utc.

  • (RangeError)

    if month is not between 1 and 12.

  • (RangeError)

    if day is not between 1 and 31.

  • (RangeError)

    if hour is not between 0 and 23.

  • (RangeError)

    if minute is not between 0 and 59.

  • (RangeError)

    if second is not between 0 and 59.

  • (RangeError)

    if sub_second is a Rational but that is less than 0 or greater than or equal to 1.


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# 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

.for(value, offset = :preserve) {|timestamp| ... } ⇒ Object

When used without a block, returns a TZInfo::Timestamp representation of a given Time, DateTime or TZInfo::Timestamp.

When called with a block, the TZInfo::Timestamp representation of value is passed to the block. The block must then return a TZInfo::Timestamp, which will be converted back to the type of the initial value. If the initial value was a TZInfo::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 TZInfo::Timestamp representation will have the same UTC offset as value), ignored (the TZInfo::Timestamp representation will have no defined UTC offset), or treated as though it were UTC (the TZInfo::Timestamp representation will have a #utc_offset of 0 and #utc? will return true).

Parameters:

  • value (Object)

    a Time, DateTime or TZInfo::Timestamp.

  • offset (Symbol) (defaults to: :preserve)

    either :preserve to preserve the offset of value, :ignore to ignore the offset of value and create a TZInfo::Timestamp with an unspecified offset, or :treat_as_utc to treat the offset of value as though it were UTC and create a UTC TZInfo::Timestamp.

Yields:

  • (timestamp)

    if a block is provided, the TZInfo::Timestamp representation is passed to the block.

Yield Parameters:

Yield Returns:

Returns:

  • (Object)

    if called without a block, the TZInfo::Timestamp representation of value, otherwise the result of the block, converted back to the type of value.

Raises:

  • (ArgumentError)

112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# 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

.utc(value, sub_second = 0) ⇒ Object

Creates a new UTC TZInfo::Timestamp.

Parameters:

  • value (Integer)

    the number of seconds since 1970-01-01 00:00:00 UTC ignoring leap seconds.

  • sub_second (Numeric) (defaults to: 0)

    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.

Raises:

  • (ArgumentError)

    if value is not an Integer.

  • (ArgumentError)

    if sub_second is not a Rational, or the Integer 0.

  • (RangeError)

    if sub_second is a Rational but that is less than 0 or greater than or equal to 1.


172
173
174
# File 'lib/tzinfo/timestamp.rb', line 172

def utc(value, sub_second = 0)
  new(value, sub_second, :utc)
end

Instance Method Details

#<=>(t) ⇒ Integer

Compares this TZInfo::Timestamp with another.

TZInfo::Timestamp instances without a defined UTC offset are not comparable with TZInfo::Timestamp instances that have a defined UTC offset.

Parameters:

Returns:

  • (Integer)

    -1, 0 or 1 depending if this instance is earlier, equal or later than t respectively. Returns nil when comparing a TZInfo::Timestamp that does not have a defined UTC offset with a TZInfo::Timestamp that does have a defined UTC offset. Returns nil if t is not a TZInfo::Timestamp.


454
455
456
457
458
459
460
461
462
# 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

#add_and_set_utc_offset(seconds, utc_offset) ⇒ Timestamp

Adds a number of seconds to the TZInfo::Timestamp value, setting the UTC offset of the result.

Parameters:

  • seconds (Integer)

    the number of seconds to be added.

  • utc_offset (Object)

    either nil for a TZInfo::Timestamp without a specified offset, an offset from UTC specified as an Integer number of seconds or the Symbol :utc).

Returns:

Raises:

  • (ArgumentError)

    if seconds is not an Integer.

  • (ArgumentError)

    if utc_offset is not nil, not an Integer and not the Symbol :utc.


372
373
374
375
376
377
# 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

#hashInteger

Returns a hash based on the value, sub-second and whether there is a defined UTC offset.

Returns:

  • (Integer)

    a hash based on the value, sub-second and whether there is a defined UTC offset.


468
469
470
# File 'lib/tzinfo/timestamp.rb', line 468

def hash
  [@value, @sub_second, !!@utc_offset].hash
end

#inspectString

Returns the internal object state as a programmer-readable String.

Returns:

  • (String)

    the internal object state as a programmer-readable String.


474
475
476
# 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

#strftime(format) ⇒ String

Formats this TZInfo::Timestamp according to the directives in the given format string.

Parameters:

  • format (String)

    the format string. Please refer to Time#strftime for a list of supported format directives.

Returns:

Raises:

  • (ArgumentError)

    if format is not specified.


426
427
428
429
# File 'lib/tzinfo/timestamp.rb', line 426

def strftime(format)
  raise ArgumentError, 'format must be specified' unless format
  to_time.strftime(format)
end

#to_datetimeDateTime

Converts this TZInfo::Timestamp to a Gregorian DateTime.

Returns:

  • (DateTime)

    a Gregorian DateTime representation of this TZInfo::Timestamp. If the UTC offset of this TZInfo::Timestamp is not specified, a UTC DateTime will be returned.


406
407
408
# File 'lib/tzinfo/timestamp.rb', line 406

def to_datetime
  new_datetime
end

#to_iInteger

Converts this TZInfo::Timestamp to an Integer number of seconds since 1970-01-01 00:00:00 UTC (ignoring leap seconds).

Returns:

  • (Integer)

    an Integer representation of this TZInfo::Timestamp (the number of seconds since 1970-01-01 00:00:00 UTC ignoring leap seconds).


415
416
417
# File 'lib/tzinfo/timestamp.rb', line 415

def to_i
  value
end

#to_sString

Returns a String representation of this TZInfo::Timestamp.

Returns:


432
433
434
435
436
437
438
439
440
441
# 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

#to_timeTime

Converts this TZInfo::Timestamp to a Time.

Returns:


391
392
393
394
395
396
397
398
399
# 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

#utcTimestamp

Returns a UTC TZInfo::Timestamp equivalent to this instance. Returns self if self.utc? is true.

Returns:


381
382
383
384
# File 'lib/tzinfo/timestamp.rb', line 381

def utc
  return self if @utc
  Timestamp.send(:new!, @value, @sub_second, :utc)
end

#utc?Boolean

Returns true if this TZInfo::Timestamp represents UTC, false if the TZInfo::Timestamp wasn't specified as UTC or nil if the TZInfo::Timestamp has no specified offset.

Returns:


355
356
357
# File 'lib/tzinfo/timestamp.rb', line 355

def utc?
  @utc
end