class DateTimeLike

Base class for DateTime::NoLeap, DateTime::AllLeap, DateTime::Fixed360Day

Constants

ABBR_DAYNAMES

@private Abbreviated day names, in English.

ABBR_MONTHNAMES

@private Abbreviated month names, in English.

DAYNAMES

@private Full names of days of the week, in English. Days of the week count from 0 to 6 (except in the commercial week); a day's numerical representation indexed into this array gives the name of that day.

MILLISECONDS_IN_DAY

@private

MILLISECONDS_IN_SECOND

@private

MONTHNAMES

@private Full month names, in English. Months count from 1 to 12; a month's numerical representation indexed into this array gives the name of that month (hence the first element is nil).

NANOSECONDS_IN_DAY

@private

NANOSECONDS_IN_SECOND

@private

SECONDS_IN_DAY

@private

Attributes

day[R]
hour[R]
mday[R]
min[R]
minute[R]
mon[R]
month[R]
offset[R]
year[R]

Public Class Methods

new(year = -4712, month = 1, day = 1, hour = 0, minute = 0, second = 0.0, offset = 0, start = nil) click to toggle source

Creates a DateTime object denoting the given calendar date.

@param year [Integer] @param month [Integer] @param day [Integer] @param hour [Integer] @param minute [Integer] @param second [Integer] @param offset [Integer] @param start [Integer]

# File lib/timesteps/datetimelike.rb, line 65
def initialize (year = -4712, month = 1, day = 1, hour = 0, minute = 0, second = 0.0, offset = 0, start = nil)
  @year   = year.to_i
  @month  = month.to_i
  @day    = day.to_i
  @hour   = hour.to_i
  @minute = minute.to_i
  @second = second
  @offset = offset
  check_valid_datetime()
end

Public Instance Methods

+(days) click to toggle source

Returns a date object pointing other days after self.

@param days [Numeric]

@return [DateTimeFixedDPY]

# File lib/timesteps/datetimelike.rb, line 190
def + (days)
  days = days.to_r + fraction 
  jday = jd.floor + days.floor
  fday = (days - days.floor)*24
  hour = fday.floor
  fday = (fday - hour)*60
  min  = fday.floor
  sec  = (fday - min)*60
  return self.class.jd(jday, hour, min, sec, offset)  
end
-(other_or_days) click to toggle source

Returns the difference between the two dates if the other is a datetime object. If the other is a numeric value, returns a date object pointing other days before self.

# File lib/timesteps/datetimelike.rb, line 205
def - (other_or_days)
  case other_or_days
  when Numeric
    return self + (-other_or_days)      
  when self.class
    return self.jd - other_or_days.jd
  else
    raise "other shoud be date-time object or numeric value"
  end
end
<<(n) click to toggle source

Returns a date object pointing n months before self.

@param n [Integer]

@return [DateTimeFixedDPY]

# File lib/timesteps/datetimelike.rb, line 230
def << (n)
  return add_months(-n)
end
<=>(other) click to toggle source

Compares the two dates and returns -1, zero, 1 or nil. The other should be a date object or a numeric value as an astronomical Julian day number.

# File lib/timesteps/datetimelike.rb, line 363
def <=> (other)
  return self.ajd <=> other.ajd
end
>>(n) click to toggle source

Returns a date object pointing n months after self.

@param n [Integer]

@return [DateTimeFixedDPY]

# File lib/timesteps/datetimelike.rb, line 221
def >> (n)
  return add_months(n)
end
ajd() click to toggle source

Calculates astronomical Julian day number.

@return [Numeric]

# File lib/timesteps/datetimelike.rb, line 159
def ajd
  return jd + fraction - @offset - 1.quo(2) 
end
compare_d(other) click to toggle source
# File lib/timesteps/datetimelike.rb, line 385
def compare_d (other)
  sday = self.day + self.fraction + self.offset
  oday = other.day + other.fraction + other.offset
  if sday > oday
    return 1
  elsif sday < oday
    return -1
  else
    return 0
  end
end
compare_md(other) click to toggle source
# File lib/timesteps/datetimelike.rb, line 367
def compare_md (other)
  sday = self.day + self.fraction + self.offset
  oday = other.day + other.fraction + other.offset
  if self.month > other.month
    return 1
  elsif self.month < other.month
    return -1
  else
    if sday > oday
      return 1
    elsif sday < oday
      return -1
    else
      return 0
    end
  end
end
difference_in_months(other) click to toggle source

Calculate difference between the object and other object in months.

@return [Integer]

# File lib/timesteps/datetimelike.rb, line 409
def difference_in_months (other)
  my    = self.new_offset(0)
  other = other.new_offset(0)
  return 12*(my.year - other.year) + my.month - other.month + my.compare_d(other).quo(2)  
end
difference_in_years(other) click to toggle source

Calculate difference between the object and other object in years.

@return [Integer]

# File lib/timesteps/datetimelike.rb, line 400
def difference_in_years (other)
  my    = self.new_offset(0)
  other = other.new_offset(0)
  return my.year - other.year + my.compare_md(other).quo(2)
end
fraction() click to toggle source

Returns time fraction in day units.

@return [Rational]

# File lib/timesteps/datetimelike.rb, line 315
def fraction ()
  return (60*(60*@hour + @minute) + @second.to_r).quo(86400)
end
inspect() click to toggle source

Returns the value as a string for inspection.

# File lib/timesteps/datetimelike.rb, line 352
def inspect
  sec  = fraction*86400
  isec = sec.floor
  fsec = ((sec - isec)*1000000).round
  offs = (offset*86400).round
  format("#<%s: %s ((%dj,%ds,%dn),%+ds)>", self.class, to_s, jd, isec, fsec, offs)
end
jd() click to toggle source

Calculates Julian day number from date part. Note that this method does not take into account the offset and time. If you need a Julian day number that takes the time into account, use ajd.

@return [Integer]

# File lib/timesteps/datetimelike.rb, line 152
def jd
  return (self.class::DPY) * (@year + 4712) + (yday - 1)
end
new_offset(offset = 0) click to toggle source

Duplicates self and resets its offset.

@param offset [Numeric]

@return [DateTime]

# File lib/timesteps/datetimelike.rb, line 128
def new_offset (offset = 0)
  gmt  = jd + fraction - @offset + offset.to_r
  jday = gmt.floor
  fday = gmt - gmt.floor
  return self.class.jd(jday, 0, 0, 0, offset) + fday
end
next()
Alias for: succ
next_day(n = 1) click to toggle source

Returns a date object pointing n days after self.

@param n [Integer]

@return [DateTimeFixedDPY]

# File lib/timesteps/datetimelike.rb, line 284
def next_day (n = 1)
  return add_days(n)
end
next_month(n = 1) click to toggle source

Returns a date object pointing n months after self.

@param n [Integer]

@return [DateTimeFixedDPY]

# File lib/timesteps/datetimelike.rb, line 257
def next_month (n = 1)
  return add_months(n)
end
next_year(n = 1) click to toggle source

Returns a date object pointing n years after self.

@param n [Integer]

@return [DateTimeFixedDPY]

# File lib/timesteps/datetimelike.rb, line 239
def next_year (n = 1)
  return self.class::new(@year+n, @month, @day, @hour, @minute, @second, @offset)
end
prev_day(n = 1) click to toggle source

Returns a date object pointing n days before self.

@param n [Integer]

@return [DateTimeFixedDPY]

# File lib/timesteps/datetimelike.rb, line 293
def prev_day (n = 1)
  return add_days(-n)
end
prev_month(n = 1) click to toggle source

Returns a date object pointing n months before self.

@param n [Integer]

@return [DateTimeFixedDPY]

# File lib/timesteps/datetimelike.rb, line 266
def prev_month (n = 1)
  return add_months(-n)
end
prev_year(n = 1) click to toggle source

Returns a date object pointing n years before self.

@param n [Integer]

@return [DateTimeFixedDPY]

# File lib/timesteps/datetimelike.rb, line 248
def prev_year (n = 1)
  return self.class::new(@year-n, @month, @day, @hour, @minute, @second, @offset)
end
sec()
Alias for: second
sec_fraction()
Alias for: second_fraction
second() click to toggle source

Returns the second (0-59)

@return [Rational]

# File lib/timesteps/datetimelike.rb, line 106
def second
  return @second.floor
end
Also aliased as: sec
second_fraction() click to toggle source

Returns the fractional part of the second.

@return [Rational]

# File lib/timesteps/datetimelike.rb, line 113
def second_fraction
  return @second.to_r - @second.floor
end
Also aliased as: sec_fraction
strftime(fmt='%F') click to toggle source
# File lib/timesteps/datetimelike_format.rb, line 132
def strftime(fmt='%F')
  
  fmt.gsub(/%([-_0^#]+)?(\d+)?([EO]?(?::{1,3}z|.))/m) do |m|
    f = {}
    a = $&
    s, w, c = $1, $2, $3
    if s
      s.scan(/./) do |k|
        case k
        when '-'; f[:p] = '-'
        when '_'; f[:p] = "\s"
        when '0'; f[:p] = '0'
        when '^'; f[:u] = true
        when '#'; f[:x] = true
        end
      end
    end
    if w
      f[:w] = w.to_i
    end
    case c
    when 'A'; emit_ad(DAYNAMES[wday], 0, f)
    when 'a'; emit_ad(ABBR_DAYNAMES[wday], 0, f)
    when 'B'; emit_ad(MONTHNAMES[month], 0, f)
    when 'b'; emit_ad(ABBR_MONTHNAMES[month], 0, f)
    when 'C', 'EC'; emit_sn((year / 100).floor, 2, f)
    when 'c', 'Ec'; emit_a(strftime('%a %b %e %H:%M:%S %Y'), 0, f)
    when 'D'; emit_a(strftime('%m/%d/%y'), 0, f)
    when 'd', 'Od'; emit_n(day, 2, f)
    when 'e', 'Oe'; emit_a(day, 2, f)
    when 'F'
      if m == '%F'
        format('%.4d-%02d-%02d', year, month, day) # 4p
      else
        emit_a(strftime('%Y-%m-%d'), 0, f)
      end
    when 'G'; emit_sn(cwyear, 4, f)
    when 'g'; emit_n(cwyear % 100, 2, f)
    when 'H', 'OH'; emit_n(hour, 2, f)
    when 'h'; emit_ad(strftime('%b'), 0, f)
    when 'I', 'OI'; emit_n((hour % 12).nonzero? || 12, 2, f)
    when 'j'; emit_n(yday, 3, f)
    when 'k'; emit_a(hour, 2, f)
    when 'L'
      emit_n((sec_fraction / MILLISECONDS_IN_SECOND).round, 3, f)
    when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
    when 'M', 'OM'; emit_n(minute, 2, f)
    when 'm', 'Om'; emit_n(month, 2, f)
    when 'N'
      emit_n((sec_fraction / NANOSECONDS_IN_SECOND).round, 9, f)
    when 'n'; "\n"
    when 'P'; emit_ad(strftime('%p').downcase, 0, f)
    when 'p'; emit_au(if hour < 12 then 'AM' else 'PM' end, 0, f)
    when 'Q'
      s = ((ajd - self::class::UNIX_EPOCH_IN_AJD) / MILLISECONDS_IN_DAY).round
      emit_sn(s, 1, f)
    when 'R'; emit_a(strftime('%H:%M'), 0, f)
    when 'r'; emit_a(strftime('%I:%M:%S %p'), 0, f)
    when 'S', 'OS'; emit_n(second.floor, 2, f)
    when 's'
      s = ((ajd - self::class::UNIX_EPOCH_IN_AJD) / SECONDS_IN_DAY).round
      emit_sn(s, 1, f)
    when 'T'
      if m == '%T'
        format('%02d:%02d:%02d', hour, minute, second) # 4p
      else
        emit_a(strftime('%H:%M:%S'), 0, f)
      end
    when 't'; "\t"
    when 'U', 'W', 'OU', 'OW'
      emit_n(if c[-1,1] == 'U' then wnum0 else wnum1 end, 2, f)
    when 'u', 'Ou'; emit_n(cwday, 1, f)
    when 'V', 'OV'; emit_n(cweek, 2, f)
    when 'v'; emit_a(strftime('%e-%b-%Y'), 0, f)
    when 'w', 'Ow'; emit_n(wday, 1, f)
    when 'X', 'EX'; emit_a(strftime('%H:%M:%S'), 0, f)
    when 'x', 'Ex'; emit_a(strftime('%m/%d/%y'), 0, f)
    when 'Y', 'EY'; emit_sn(year, 4, f)
    when 'y', 'Ey', 'Oy'; emit_n(year % 100, 2, f)
    when 'Z'; emit_au(strftime('%:z'), 0, f)
    when /\A(:{0,3})z/
      t = $1.size
      sign = if offset < 0 then -1 else +1 end
      fr = offset.abs
      ss = fr.div(SECONDS_IN_DAY) # 4p
      hh, ss = ss.divmod(3600)
      mm, ss = ss.divmod(60)
      if t == 3
        if    ss.nonzero? then t =  2
        elsif mm.nonzero? then t =  1
        else                   t = -1
        end
      end
      case t
      when -1
        tail = []
        sep = ''
      when 0
        f[:w] -= 2 if f[:w]
        tail = ['%02d' % mm]
        sep = ''
      when 1
        f[:w] -= 3 if f[:w]
        tail = ['%02d' % mm]
        sep = ':'
      when 2
        f[:w] -= 6 if f[:w]
        tail = ['%02d' % mm, '%02d' % ss]
        sep = ':'
      end
      ([emit_z(sign * hh, 2, f)] + tail).join(sep)
    when '%'; emit_a('%', 0, f)
    when '+'; emit_a(strftime('%a %b %e %H:%M:%S %Z %Y'), 0, f)
    else
      a
    end
  end
end
succ() click to toggle source

Returns a datetime object denoting the following day.

@return [DateTime]

# File lib/timesteps/datetimelike.rb, line 306
def succ
  return add_days(1)
end
Also aliased as: next
to_s() click to toggle source

Returns a string in an ISO 8601 format.

# File lib/timesteps/datetimelike.rb, line 342
def to_s
  format("%04d-%02d-%02dT%02d:%02d:%02d%s%s",
         @year, @month, @day, 
         @hour, @minute, @second.floor, 
         format_microsec, 
         format_offset)
end
wday() click to toggle source

Returns the day of week (0-6, Sunday is zero).

@return [Integer]

# File lib/timesteps/datetimelike.rb, line 166
def wday 
  return (jd + 1 ) % 7
end
yday() click to toggle source

Returns Day of Year

@return [Integer]

# File lib/timesteps/datetimelike.rb, line 138
def yday
  dpm = self.class::DPM
  doy = @day
  (@month-1).step(1,-1) do |m|
    doy += dpm[m]
  end    
  return doy
end

Private Instance Methods

add_days(days) click to toggle source
# File lib/timesteps/datetimelike.rb, line 297
def add_days (days)
  return self.class::jd(jd+days.to_i, @hour, @minute, @second, @offset)
end
add_months(months) click to toggle source
# File lib/timesteps/datetimelike.rb, line 270
def add_months (months)
  months = (@month + months).to_i - 1
  years  = months / 12
  month  = months % 12 + 1
  return self.class::new(@year+years, month, @day, @hour, @minute, @second, @offset)
end
check_valid_datetime() click to toggle source
# File lib/timesteps/datetimelike.rb, line 76
def check_valid_datetime
  unless valid_date?
    raise "invalid date for #{self.class} [year: #{@year}, month: #{@month}, day: #{@day}]"
  end
  unless valid_time?
    raise "invalid time for #{self.class} [hour: #{@hour}, minute: #{@minute}, second: #{@second}]"
  end
end
commercial() click to toggle source

Returns the day of week (0-6, Sunday is zero).

@return [Integer]

# File lib/timesteps/datetimelike.rb, line 173
def commercial
  jd0 = (self.class::DPY) * (@year + 4712)
  wday0 = (jd0 + 1 ) % 7
  cwyear = @year
  yday1  = yday - wday0
  cweek = yday / 7 + 1
  cwday = yday % 7 + 1
  return cwyear, cweek, cwday
end
format_microsec() click to toggle source
# File lib/timesteps/datetimelike.rb, line 329
def format_microsec
  microsec = ((@second - @second.floor)*1000000).round 
  if microsec == 0
    ""
  else
    ".%06d" % microsec
  end
end
format_offset() click to toggle source
# File lib/timesteps/datetimelike.rb, line 319
def format_offset
  oh = @offset*24
  return [
    oh >= 0 ? "+" : "-", 
    "%02i" % oh.abs.to_i, 
    ":",
    "%02i" % ((oh.abs - oh.abs.to_i)*60).round
  ].join("")    
end
valid_time?() click to toggle source
# File lib/timesteps/datetimelike.rb, line 85
def valid_time?
  begin
    DateTime.new(2001, 1, 1, @hour, @minute, @second)
    true
  rescue
    false
  end
end