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



342
343
344
345
346
347
348
# File 'lib/tzinfo/timestamp.rb', line 342

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.



319
320
321
# File 'lib/tzinfo/timestamp.rb', line 319

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.



323
324
325
# File 'lib/tzinfo/timestamp.rb', line 323

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



314
315
316
# File 'lib/tzinfo/timestamp.rb', line 314

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



54
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
# File 'lib/tzinfo/timestamp.rb', line 54

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


110
111
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
# File 'lib/tzinfo/timestamp.rb', line 110

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.



170
171
172
# File 'lib/tzinfo/timestamp.rb', line 170

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.



452
453
454
455
456
457
458
459
460
# File 'lib/tzinfo/timestamp.rb', line 452

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.



370
371
372
373
374
375
# File 'lib/tzinfo/timestamp.rb', line 370

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.



466
467
468
# File 'lib/tzinfo/timestamp.rb', line 466

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.



472
473
474
# File 'lib/tzinfo/timestamp.rb', line 472

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.



424
425
426
427
# File 'lib/tzinfo/timestamp.rb', line 424

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

#to_datetimeDateTime

Converts this TZInfo::Timestamp to a DateTime.

Returns:



404
405
406
# File 'lib/tzinfo/timestamp.rb', line 404

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



413
414
415
# File 'lib/tzinfo/timestamp.rb', line 413

def to_i
  value
end

#to_sString

Returns a String representation of this TZInfo::Timestamp.

Returns:



430
431
432
433
434
435
436
437
438
439
# File 'lib/tzinfo/timestamp.rb', line 430

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:



389
390
391
392
393
394
395
396
397
# File 'lib/tzinfo/timestamp.rb', line 389

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:



379
380
381
382
# File 'lib/tzinfo/timestamp.rb', line 379

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:



353
354
355
# File 'lib/tzinfo/timestamp.rb', line 353

def utc?
  @utc
end