Class: ThirdBase::DateTime

Inherits:
Date
  • Object
show all
Defined in:
lib/third_base/datetime.rb

Overview

ThirdBase’s DateTime class, which builds on the Date class and adds a time component of hours, minutes, seconds, microseconds, and an offset from UTC.

Constant Summary collapse

PARSER_LIST =
[]
DEFAULT_PARSER_LIST =
[:time, :iso, :us, :num]
DEFAULT_PARSERS =
{}
TIME_RE_STRING =
'(?:[T ]?([\d ]?\d):(\d\d)(?::(\d\d(\.\d+)?))?([ap]m?)? ?(Z|[+-](?:\d\d:?(?:\d\d)?))?)?'
STRPTIME_PROC_H =
proc{|h,x| h[:hour] = x.to_i}
STRPTIME_PROC_M =
proc{|h,x| h[:min] = x.to_i}
STRPTIME_PROC_P =
proc{|h,x| h[:meridian] = x.downcase == 'pm' ? :pm : :am}
STRPTIME_PROC_S =
proc{|h,x| h[:sec] = x.to_i}
STRPTIME_PROC_s =
proc do |h,x|
  j, i = x.to_i.divmod(86400)
  hours, i = i.divmod(3600)
  minutes, seconds = i.divmod(60)
  h.merge!(:jd=>j+UNIXEPOCH, :hour=>hours, :min=>minutes, :sec=>seconds)
end
STRPTIME_PROC_z =
proc{|h,x| x=x.gsub(':',''); h[:offset] = (x == 'Z' ? 0 : x[0..2].to_i*3600 + x[3..4].to_i*60)}

Constants inherited from Date

ThirdBase::Date::ABBR_DAYNAMES, ThirdBase::Date::ABBR_DAYNAME_RE_PATTERN, ThirdBase::Date::ABBR_MONTHNAMES, ThirdBase::Date::ABBR_MONTHNAME_RE_PATTERN, ThirdBase::Date::CUMMULATIVE_MONTH_DAYS, ThirdBase::Date::DAYNAMES, ThirdBase::Date::DAYS_IN_MONTH, ThirdBase::Date::DAY_NUM_MAP, ThirdBase::Date::FULL_DAYNAME_RE_PATTERN, ThirdBase::Date::FULL_MONTHNAME_RE_PATTERN, ThirdBase::Date::LEAP_CUMMULATIVE_MONTH_DAYS, ThirdBase::Date::LEAP_DAYS_IN_MONTH, ThirdBase::Date::MONTHNAMES, ThirdBase::Date::MONTHNAME_RE_PATTERN, ThirdBase::Date::MONTH_NUM_MAP, ThirdBase::Date::PARSERS, ThirdBase::Date::STRFTIME_RE, ThirdBase::Date::STRPTIME_PROC_A, ThirdBase::Date::STRPTIME_PROC_B, ThirdBase::Date::STRPTIME_PROC_C, ThirdBase::Date::STRPTIME_PROC_G, ThirdBase::Date::STRPTIME_PROC_V, ThirdBase::Date::STRPTIME_PROC_Y, ThirdBase::Date::STRPTIME_PROC_d, ThirdBase::Date::STRPTIME_PROC_g, ThirdBase::Date::STRPTIME_PROC_j, ThirdBase::Date::STRPTIME_PROC_m, ThirdBase::Date::STRPTIME_PROC_u, ThirdBase::Date::STRPTIME_PROC_y, ThirdBase::Date::UNIXEPOCH

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Date

#<<, #===, #>>, add_parser, add_parser_type, #cwday, #cweek, #cwyear, #day, #downto, #hash, #inspect, #jd, #leap?, #mon, new, new!, parse, reset_parsers!, #step, #strftime, strptime, #succ, #to_s, today, #upto, use_parsers, #wday, #yday, #year

Constructor Details

#initialize(opts) ⇒ DateTime

Called by DateTime.new!, should be a hash with the following possible keys:

  • :civil, :commericial, :jd, :ordinal : See ThirdBase::Date#initialize

  • :fract : The fraction of the day (0.5 is Noon)

  • :offset : offset from UTC, in seconds.

  • :parts : an array with 4 elements, hour, minute, second, and microsecond

Raises an ArgumentError if an invalid date is used. DateTime objects are immutable once created.

Raises:

  • (ArgumentError)


235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/third_base/datetime.rb', line 235

def initialize(opts)
  @not_parsed = opts[:not_parsed] || []
  @offset = opts[:offset]
  raise(ArgumentError, 'invalid datetime') unless @offset.is_a?(Integer) and @offset <= 43200 and @offset >= -43200
  if opts[:parts]
    @hour, @min, @sec, @usec = opts[:parts]
    raise(ArgumentError, 'invalid datetime') unless @hour.is_a?(Integer) and @min.is_a?(Integer) and @sec.is_a?(Integer) and @usec.is_a?(Integer)
  elsif opts[:fract]
    @fract = opts[:fract]
    raise(ArgumentError, 'invalid datetime') unless @fract.is_a?(Float) and @fract < 1.0 and @fract >= 0.0
  else
    raise(ArgumentError, 'invalid datetime')
  end
  super(opts)
end

Instance Attribute Details

#not_parsedObject (readonly)

Which parts of this datetime were guessed instead of being parsed from the input.



225
226
227
# File 'lib/third_base/datetime.rb', line 225

def not_parsed
  @not_parsed
end

#offsetObject (readonly) Also known as: utc_offset

This datetime’s offset from UTC, in seconds.



221
222
223
# File 'lib/third_base/datetime.rb', line 221

def offset
  @offset
end

Class Method Details

.civil(year, mon, day, hour = 0, min = 0, sec = 0, usec = 0, offset = 0) ⇒ Object

Create a new DateTime with the given year, month, day of month, hour, minute, second, microsecond and offset.



66
67
68
# File 'lib/third_base/datetime.rb', line 66

def self.civil(year, mon, day, hour=0, min=0, sec=0, usec=0, offset=0)
  new!(:civil=>[year, mon, day], :parts=>[hour, min, sec, usec], :offset=>offset)
end

.commercial(cwyear, cweek, cwday = 5, hour = 0, min = 0, sec = 0, usec = 0, offset = 0) ⇒ Object

Create a new DateTime with the given commercial week year, commercial week, commercial week day, hour, minute second, microsecond, and offset.



72
73
74
# File 'lib/third_base/datetime.rb', line 72

def self.commercial(cwyear, cweek, cwday=5, hour=0, min=0, sec=0, usec=0, offset=0)
  new!(:commercial=>[cwyear, cweek, cwday], :parts=>[hour, min, sec, usec], :offset=>offset)
end

.hour_with_meridian(hour, meridian) ⇒ Object

Raises:

  • (ArgumentError)


161
162
163
164
165
166
167
168
# File 'lib/third_base/datetime.rb', line 161

def self.hour_with_meridian(hour, meridian)
  raise(ArgumentError, 'invalid date') unless hour and hour >= 1 and hour <= 12
  if meridian == :am
    hour == 12 ? 0 : hour
  else
    hour < 12 ? hour + 12 : hour 
  end
end

.jd(jd, hour = 0, min = 0, sec = 0, usec = 0, offset = 0) ⇒ Object

Create a new DateTime with the given julian date, hour, minute, second, microsecond, and offset.



77
78
79
# File 'lib/third_base/datetime.rb', line 77

def self.jd(jd, hour=0, min=0, sec=0, usec=0, offset=0)
  new!(:jd=>jd, :parts=>[hour, min, sec, usec], :offset=>offset)
end

.jd_fract(jd, fract = 0.0, offset = 0) ⇒ Object

Create a new DateTime with the given julian day, fraction of the day (0.5 is Noon), and offset.



82
83
84
# File 'lib/third_base/datetime.rb', line 82

def self.jd_fract(jd, fract=0.0, offset=0)
  new!(:jd=>jd, :fract=>fract, :offset=>offset)
end

.nowObject

Create a new DateTime with the current date and time.



87
88
89
90
# File 'lib/third_base/datetime.rb', line 87

def self.now
  t = Time.now
  new!(:civil=>[t.year, t.mon, t.day], :parts=>[t.hour, t.min, t.sec, t.usec], :offset=>t.utc_offset)
end

.ordinal(year, yday, hour = 0, min = 0, sec = 0, usec = 0, offset = 0) ⇒ Object

Create a new DateTime with the given year, day of year, hour, minute, second, microsecond, and offset.



93
94
95
# File 'lib/third_base/datetime.rb', line 93

def self.ordinal(year, yday, hour=0, min=0, sec=0, usec=0, offset=0)
  new!(:ordinal=>[year, yday], :parts=>[hour, min, sec, usec], :offset=>offset)
end

Instance Method Details

#+(d) ⇒ Object

Return a new datetune with the given number of days added to this datetime. If d is a Float adds a fractional date, with possible loss of precision. If d is an integer, the returned date has the same time components as the current date. In both cases, the offset for the new date is the same as for this date.



255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/third_base/datetime.rb', line 255

def +(d)
  case d
  when Float
    d, f = d.to_f.divmod(1)
    f = fract + f
    m, f = f.divmod(1)
    self.class.jd_fract(jd+d+m, f, @offset)
  when Integer
    new_jd(jd+d)
  else
    raise(TypeError, "d must be a Float or Integer")
  end
end

#-(d) ⇒ Object

Return a new datetune with the given number of days subtracted from this datetime. If d is a DateTime, returns the difference between the two datetimes as a Float, considering both datetimes date, time, and offest.



272
273
274
275
276
277
278
279
280
281
# File 'lib/third_base/datetime.rb', line 272

def -(d)
  case d
  when self.class
    (jd - d.jd) + (fract - d.fract) + (@offset - d.offset)/86400.0
  when Integer, Float
    self + -d
  else
    raise TypeError, "d should be #{self.class}, Float, or Integer"
  end
end

#<=>(datetime) ⇒ Object

Compares two datetimes. If the given datetime is an Integer, returns 1 unless this datetime’s time components are all 0, in which case it returns 0. If the given datetime is a Float, calculates this date’s julian date plus the date fraction and compares it to the given datetime, and returns 0 only if the two are very close together. This code does not take into account time offsets.



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/third_base/datetime.rb', line 288

def <=>(datetime)
  case datetime
  when Integer
    if ((d = (jd <=> datetime)) == 0)
      (hour == 0 and min == 0 and sec == 0 and usec == 0) ? 0 : 1
    else
      d
    end
  when Float
    diff = jd+fract - datetime
    if diff.abs <= 1.15740740740741e-011
      0
    else
      diff > 0.0 ? 1 : -1
    end
  when self.class
    ((d = super) == 0) && ((d = (hour <=> datetime.hour)) == 0) && ((d = (min <=> datetime.min)) == 0) && ((d = (sec <=> datetime.sec)) == 0) && ((d = (usec <=> datetime.usec)) == 0)
    d
  else
    raise TypeError, "d should be #{self.class}, Float, or Integer"
  end
end

#==(datetime) ⇒ Object Also known as: eql?

Two DateTimes are equal only if their dates and time components are the same, not counting the offset.



312
313
314
315
# File 'lib/third_base/datetime.rb', line 312

def ==(datetime)
  return false unless DateTime === datetime
  super and hour == datetime.hour and min == datetime.min and sec == datetime.sec and usec == datetime.usec 
end

#fractObject

Returns the fraction of the day for this datetime (Noon is 0.5)



319
320
321
# File 'lib/third_base/datetime.rb', line 319

def fract
  @fract ||= (@hour*3600+@min*60+@sec+@usec/1000000.0)/86400.0
end

#hourObject

Returns the hour of this datetime.



324
325
326
# File 'lib/third_base/datetime.rb', line 324

def hour
  @hour ||= time_parts[0]
end

#minObject

Returns the minute of this datetime.



329
330
331
# File 'lib/third_base/datetime.rb', line 329

def min
  @min ||= time_parts[1]
end

#secObject

Returns the second of this datetime.



334
335
336
# File 'lib/third_base/datetime.rb', line 334

def sec
  @sec ||= time_parts[2]
end

#usecObject

Returns the microsecond of this datetime.



339
340
341
# File 'lib/third_base/datetime.rb', line 339

def usec
  @usec ||= time_parts[3]
end

#zoneObject

Return the offset as a time zone string (+/-HHMM).



344
345
346
# File 'lib/third_base/datetime.rb', line 344

def zone
  strftime('%z')
end