Class: TimeCrisis::DateTime

Inherits:
Date show all
Extended by:
NthWeekday::ClassMethods
Defined in:
lib/time_crisis/datetime.rb,
lib/time_crisis/to_json.rb,
lib/time_crisis/support/ext/date_time/zones.rb,
lib/time_crisis/support/ext/date_time/acts_like.rb,
lib/time_crisis/support/ext/date_time/conversions.rb,
lib/time_crisis/support/ext/date_time/calculations.rb

Overview

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

Constant Summary collapse

TIME_ZONE_SECOND_OFFSETS =
{
'UTC'=>0, 'Z'=>0, 'UT'=>0, 'GMT'=>0,
'EST'=>-18000, 'EDT'=>-14400, 'CST'=>-21600, 'CDT'=>-18000, 'MST'=>-25200, 'MDT'=>-21600, 'PST'=>-28800, 'PDT'=>-25200,
'A'=>3600, 'B'=>7200, 'C'=>10800, 'D'=>14400, 'E'=>18000, 'F'=>21600, 'G'=>25200, 'H'=>28800, 'I'=>32400, 'K'=>36000, 'L'=>39600, 'M'=>43200,
'N'=>-3600, 'O'=>-7200, 'P'=>-10800, 'Q'=>-14400, 'R'=>-18000, 'S'=>-21600, 'T'=>-25200, 'U'=>-28800, 'V'=>-32400, 'W'=>-36000, 'X'=>-39600, 'Y'=>-43200}
PARSER_LIST =
[]
DEFAULT_PARSER_LIST =
[:time, :iso, :us, :num]
DEFAULT_PARSERS =
{}
TIME_ZONE_RE_STRING =
"(#{TIME_ZONE_SECOND_OFFSETS.keys.sort.join('|')}|[+-](?:\\d\\d:?(?:\\d\\d)?))"
TIME_RE_STRING =
"(?:[T ]?([\\d ]?\\d):(\\d\\d)(?::(\\d\\d(\\.\\d+)?))?([ap]m?)? ?#{TIME_ZONE_RE_STRING}?)?"
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 {|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)
}
STRPTIME_PROC_z =
proc {|h,x| h[:offset] = convert_parsed_offset(x)}

Constants inherited from Date

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from NthWeekday::ClassMethods

nth_weekday

Methods inherited from Date

#<<, #===, #>>, add_parser, add_parser_type, #beginning_of_month, #beginning_of_quarter, #beginning_of_week, #beginning_of_year, #cwday, #cweek, #cwyear, #day, #days_in_month, #downto, #end_of_month, #end_of_quarter, #end_of_week, #end_of_year, #hash, #jd, #last_month, #last_year, #leap?, #minus_with_duration, #mon, #months_ago, #months_since, new, new!, #next_month, #next_week, #next_year, parse, #plus_with_duration, reset_parsers!, #step, #strftime, strptime, #succ, today, #today?, tomorrow, #tomorrow, #upto, use_parsers, #wday, #yday, #year, #years_ago, #years_since, yesterday, #yesterday

Methods included from TimeCrisis::DateRange::Date::ClassMethods

#range

Methods included from NamedMonths

#april, #august, #december, #february, #january, #july, #june, #march, #may, #month_range, #november, #october, #september

Methods included from MeteorologicalSeasons::ClassMethods

#beginning_of_meteorological_autumn, #beginning_of_meteorological_spring, #beginning_of_meteorological_summer, #beginning_of_meteorological_winter

Constructor Details

#initialize(opts) ⇒ DateTime

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

  • :civil, :commericial, :jd, :ordinal : See TimeCrisis::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)


267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/time_crisis/datetime.rb', line 267

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.



257
258
259
# File 'lib/time_crisis/datetime.rb', line 257

def not_parsed
  @not_parsed
end

#offsetObject (readonly) Also known as: utc_offset

This datetime’s offset from UTC, in seconds.



243
244
245
# File 'lib/time_crisis/datetime.rb', line 243

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.



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

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.



78
79
80
# File 'lib/time_crisis/datetime.rb', line 78

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

.currentObject



10
11
12
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 10

def current
  ::TimeCrisis::Time.zone_default ? ::TimeCrisis::Time.zone.now.to_tc_datetime : ::TimeCrisis::Time.now.to_tc_datetime
end

.hour_with_meridian(hour, meridian) ⇒ Object

Raises:

  • (ArgumentError)


166
167
168
169
170
171
172
173
# File 'lib/time_crisis/datetime.rb', line 166

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.



83
84
85
# File 'lib/time_crisis/datetime.rb', line 83

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.



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

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

.local_offsetObject



6
7
8
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 6

def local_offset
  ::TimeCrisis::Time.local(2007).utc_offset
end

.nowObject

Create a new DateTime with the current date and time.



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

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.



99
100
101
# File 'lib/time_crisis/datetime.rb', line 99

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.



287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/time_crisis/datetime.rb', line 287

def +(d)
  case
  when d.is_a?(Integer)
    new_jd(jd+d)
  when d.respond_to?(:to_f)
    d, f = d.to_f.divmod(1)
    f = fract + f
    m, f = f.divmod(1)
    self.class.jd_fract(jd+d+m, f, @offset)
  else
    raise TypeError, "d must be an Integer or respond to :to_f"
  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.



304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/time_crisis/datetime.rb', line 304

def -(d)
  case
  when d.is_a?(::TimeCrisis::DateTime)
    (jd - d.jd) + (fract - d.fract) + (@offset - d.offset)/86400.0
  when d.is_a?(Integer)
    self + -d
  when d.respond_to?(:to_f)
    self + -(d.to_f)
  else
    raise TypeError, "d should be a TimeCrisis::DateTime, Integer, or respond to :to_f"
  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.



346
347
348
349
# File 'lib/time_crisis/datetime.rb', line 346

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

#acts_like_date?Boolean

Returns:

  • (Boolean)


5
6
7
# File 'lib/time_crisis/support/ext/date_time/acts_like.rb', line 5

def acts_like_date?
  true
end

#acts_like_time?Boolean

Returns:

  • (Boolean)


9
10
11
# File 'lib/time_crisis/support/ext/date_time/acts_like.rb', line 9

def acts_like_time?
  true
end

#advance(options) ⇒ Object



40
41
42
43
44
45
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 40

def advance(options)
  d = to_tc_date.advance(options)
  datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
  seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600
  seconds_to_advance == 0 ? datetime_advanced_by_date : datetime_advanced_by_date.since(seconds_to_advance)
end

#ago(seconds) ⇒ Object



47
48
49
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 47

def ago(seconds)
  since(-seconds)
end

#beginning_of_dayObject Also known as: midnight, at_midnight, at_beginning_of_day



56
57
58
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 56

def beginning_of_day
  change(:hour => 0)
end

#change(options = {}) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 27

def change(options={})
  ::TimeCrisis::DateTime.civil(
    options[:year] || year,
    options[:month] || month,
    options[:day] || day,
    options[:hour] || hour,
    options[:min] || (options[:hour] ? 0 : min),
    options[:sec] || ((options[:hour] || options[:min]) ? 0 : sec),
    options[:usec] || ((options[:hour] || options[:min] || options[:sec]) ? 0 : usec),
    options[:offset] || offset
  )
end

#compare_with_coercion(other) ⇒ Object Also known as: <=>



80
81
82
83
84
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 80

def compare_with_coercion(other)
  other = other.comparable_time if other.respond_to?(:comparable_time)
  other = other.to_tc_datetime unless other.acts_like?(:date)
  compare_without_coercion(other)
end

#end_of_dayObject



63
64
65
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 63

def end_of_day
  change(:hour => 23, :min => 59, :sec => 59)
end

#formatted_offset(colon = true, alternate_utc_string = nil) ⇒ Object



13
14
15
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 13

def formatted_offset(colon = true, alternate_utc_string = nil)
  utc? && alternate_utc_string || TimeCrisis::TimeZone.seconds_to_utc_offset(utc_offset, colon)
end

#fractObject

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



353
354
355
# File 'lib/time_crisis/datetime.rb', line 353

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

#future?Boolean

Returns:

  • (Boolean)


19
20
21
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 19

def future?
  self > ::TimeCrisis::DateTime.current
end

#hourObject

Returns the hour of this datetime.



358
359
360
# File 'lib/time_crisis/datetime.rb', line 358

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

#in_time_zone(zone = ::TimeCrisis::Time.zone) ⇒ Object



3
4
5
# File 'lib/time_crisis/support/ext/date_time/zones.rb', line 3

def in_time_zone(zone = ::TimeCrisis::Time.zone)
  TimeCrisis::TimeWithZone.new(utc? ? self : getutc, ::TimeCrisis::Time.__send__(:get_zone, zone))
end

#minObject

Returns the minute of this datetime.



363
364
365
# File 'lib/time_crisis/datetime.rb', line 363

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

#new_offset(of) ⇒ Object

compatibility method for TZInfo



247
248
249
250
251
252
253
254
# File 'lib/time_crisis/datetime.rb', line 247

def new_offset(of)
  if of.is_a?(Rational)
    of = (1 + of) if of < 0
    of = of * 86400
  end

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

#past?Boolean

Returns:

  • (Boolean)


15
16
17
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 15

def past?
  self < ::TimeCrisis::DateTime.current
end

#readable_inspectObject Also known as: inspect



17
18
19
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 17

def readable_inspect
  "#<TimeCrisis::DateTime #{self.to_s(:rfc822)}>"
end

#secObject

Returns the second of this datetime.



368
369
370
# File 'lib/time_crisis/datetime.rb', line 368

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

#seconds_since_midnightObject



23
24
25
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 23

def seconds_since_midnight
  sec + (min * 60) + (hour * 3600)
end

#since(seconds) ⇒ Object Also known as: in



51
52
53
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 51

def since(seconds)
  self + Rational(seconds.round, 86400).to_f
end

#to_dateObject



23
24
25
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 23

def to_date
  ::Date.civil(year, month, day)
end

#to_datetimeObject



35
36
37
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 35

def to_datetime
  ::DateTime.civil(year, month, day, hour, min, second, Rational(offset, 86400))
end

#to_fObject



51
52
53
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 51

def to_f
  seconds_since_unix_epoch.to_f
end

#to_formatted_s(format = :default) ⇒ Object Also known as: to_s



3
4
5
6
7
8
9
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 3

def to_formatted_s(format = :default)
  if formatter = ::TimeCrisis::Time::DATE_FORMATS[format]
    formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
  else
    to_default_s
  end
end

#to_iObject



55
56
57
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 55

def to_i
  seconds_since_unix_epoch.to_i
end

#to_json(options = nil) ⇒ Object



9
10
11
# File 'lib/time_crisis/to_json.rb', line 9

def to_json(options = nil)
  xmlschema.inspect
end

#to_tc_dateObject



27
28
29
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 27

def to_tc_date
  ::TimeCrisis::Date.civil(year, month, day)
end

#to_tc_datetimeObject



31
32
33
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 31

def to_tc_datetime
  self
end

#to_tc_timeObject



43
44
45
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 43

def to_tc_time
  ::TimeCrisis::Time.at(self.to_f)
end

#to_timeObject



39
40
41
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 39

def to_time
  ::Time.at(self.to_f)
end

#usecObject

Returns the microsecond of this datetime.



373
374
375
# File 'lib/time_crisis/datetime.rb', line 373

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

#utcObject Also known as: getutc



67
68
69
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 67

def utc
  new_offset(0)
end

#utc?Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/time_crisis/support/ext/date_time/calculations.rb', line 72

def utc?
  offset == 0
end

#xmlschemaObject



47
48
49
# File 'lib/time_crisis/support/ext/date_time/conversions.rb', line 47

def xmlschema
  strftime("%Y-%m-%dT%H:%M:%S%Z")
end

#zoneObject

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



378
379
380
# File 'lib/time_crisis/datetime.rb', line 378

def zone
  strftime('%Z')
end