mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-08-15 03:26:00 -07:00
520 lines
10 KiB
Ruby
520 lines
10 KiB
Ruby
class Time
|
|
include Comparable
|
|
|
|
def self.now
|
|
Rubinius.primitive :time_s_now
|
|
raise PrimitiveFailure, "Time.now primitive failed"
|
|
end
|
|
|
|
def self.duplicate(other)
|
|
Rubinius.primitive :time_s_dup
|
|
raise ArgumentError, "descriptors reference invalid time"
|
|
end
|
|
|
|
def self.specific(sec, nsec, from_gmt, offset)
|
|
Rubinius.primitive :time_s_specific
|
|
raise ArgumentError, "descriptors reference invalid time"
|
|
end
|
|
|
|
def dup
|
|
self.class.duplicate(self)
|
|
end
|
|
|
|
def seconds
|
|
Rubinius.primitive :time_seconds
|
|
raise PrimitiveFailure, "Time#second primitive failed"
|
|
end
|
|
|
|
def usec
|
|
Rubinius.primitive :time_useconds
|
|
raise PrimitiveFailure, "Time#usec primitive failed"
|
|
end
|
|
|
|
def to_a
|
|
Rubinius.primitive :time_decompose
|
|
raise PrimitiveFailure, "Time#to_a primitive failed"
|
|
end
|
|
|
|
def strftime(format)
|
|
Rubinius.primitive :time_strftime
|
|
raise PrimitiveFailure, "Time#strftime primitive failed"
|
|
end
|
|
|
|
def self.at(sec, usec=undefined)
|
|
if undefined.equal?(usec)
|
|
if sec.kind_of?(Time)
|
|
return duplicate(sec)
|
|
elsif sec.kind_of?(Integer)
|
|
return specific(sec, 0, false, nil)
|
|
end
|
|
end
|
|
|
|
if sec.kind_of?(Time) && usec.kind_of?(Integer)
|
|
raise TypeError, "can't convert Time into an exact number"
|
|
end
|
|
|
|
usec = 0 if undefined.equal?(usec)
|
|
|
|
s = Rubinius::Type.coerce_to_exact_num(sec)
|
|
u = Rubinius::Type.coerce_to_exact_num(usec)
|
|
|
|
sec = s.to_i
|
|
nsec_frac = s % 1.0
|
|
|
|
sec -= 1 if s < 0 && nsec_frac > 0
|
|
nsec = (nsec_frac * 1_000_000_000 + 0.5).to_i + (u * 1000).to_i
|
|
|
|
sec += nsec / 1_000_000_000
|
|
nsec %= 1_000_000_000
|
|
|
|
specific(sec, nsec, false, nil)
|
|
end
|
|
|
|
def self.from_array(sec, min, hour, mday, month, year, nsec, is_dst, from_gmt, utc_offset)
|
|
Rubinius.primitive :time_s_from_array
|
|
|
|
if sec.kind_of?(String)
|
|
sec = sec.to_i
|
|
elsif nsec
|
|
sec = Rubinius::Type.coerce_to(sec || 0, Integer, :to_int)
|
|
else
|
|
s = Rubinius::Type.coerce_to_exact_num(sec || 0)
|
|
|
|
sec = s.to_i
|
|
nsec_frac = s % 1.0
|
|
|
|
if s < 0 && nsec_frac > 0
|
|
sec -= 1
|
|
end
|
|
|
|
nsec = (nsec_frac * 1_000_000_000 + 0.5).to_i
|
|
end
|
|
|
|
nsec ||= 0
|
|
sec += nsec / 1_000_000_000
|
|
nsec %= 1_000_000_000
|
|
|
|
if utc_offset
|
|
utc_offset_sec = utc_offset.to_i
|
|
utc_offset_nsec = ((utc_offset % 1.0) * 1_000_000_000 + 0.5).to_i
|
|
else
|
|
utc_offset_sec = 0
|
|
utc_offset_nsec = 0
|
|
end
|
|
|
|
from_array(sec, min, hour, mday, month, year, nsec, is_dst, from_gmt, utc_offset, utc_offset_sec, utc_offset_nsec)
|
|
end
|
|
|
|
def self.new(year=undefined, month=nil, day=nil, hour=nil, minute=nil, second=nil, utc_offset=nil)
|
|
if undefined.equal?(year)
|
|
now
|
|
elsif utc_offset == nil
|
|
compose(:local, year, month, day, hour, minute, second)
|
|
else
|
|
compose(Rubinius::Type.coerce_to_utc_offset(utc_offset), year, month, day, hour, minute, second)
|
|
end
|
|
end
|
|
|
|
def inspect
|
|
if @is_gmt
|
|
str = strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
else
|
|
str = strftime("%Y-%m-%d %H:%M:%S %z")
|
|
end
|
|
|
|
str.force_encoding Encoding::US_ASCII
|
|
end
|
|
|
|
alias_method :to_s, :inspect
|
|
|
|
def nsec
|
|
Rubinius.primitive :time_nseconds
|
|
raise PrimitiveFailure, "Time#nsec primitive failed"
|
|
end
|
|
|
|
def nsec=(nanoseconds)
|
|
Rubinius.primitive :time_set_nseconds
|
|
raise PrimitiveFailure, "Time#nsec= primitive failed"
|
|
end
|
|
private :nsec=
|
|
|
|
alias_method :tv_nsec, :nsec
|
|
|
|
def subsec
|
|
if nsec == 0
|
|
0
|
|
else
|
|
Rational(nsec, 1_000_000_000)
|
|
end
|
|
end
|
|
|
|
def sunday?
|
|
wday == 0
|
|
end
|
|
|
|
def monday?
|
|
wday == 1
|
|
end
|
|
|
|
def tuesday?
|
|
wday == 2
|
|
end
|
|
|
|
def wednesday?
|
|
wday == 3
|
|
end
|
|
|
|
def thursday?
|
|
wday == 4
|
|
end
|
|
|
|
def friday?
|
|
wday == 5
|
|
end
|
|
|
|
def saturday?
|
|
wday == 6
|
|
end
|
|
|
|
def to_r
|
|
(seconds + subsec).to_r
|
|
end
|
|
|
|
def to_f
|
|
to_r.to_f
|
|
end
|
|
|
|
def +(other)
|
|
raise TypeError, 'time + time?' if other.kind_of?(Time)
|
|
|
|
case other = Rubinius::Type.coerce_to_exact_num(other)
|
|
when Integer
|
|
other_sec = other
|
|
other_nsec = 0
|
|
else
|
|
other_sec, nsec_frac = other.divmod(1)
|
|
other_nsec = (nsec_frac * 1_000_000_000).to_i
|
|
end
|
|
|
|
# Don't use self.class, MRI doesn't honor subclasses here
|
|
Time.specific(seconds + other_sec, nsec + other_nsec, @is_gmt, @offset)
|
|
end
|
|
|
|
def -(other)
|
|
if other.kind_of?(Time)
|
|
return (seconds - other.seconds) + ((nsec - other.nsec) * 0.000000001)
|
|
end
|
|
|
|
case other = Rubinius::Type.coerce_to_exact_num(other)
|
|
when Integer
|
|
other_sec = other
|
|
other_nsec = 0
|
|
else
|
|
other_sec, nsec_frac = other.divmod(1)
|
|
other_nsec = (nsec_frac * 1_000_000_000 + 0.5).to_i
|
|
end
|
|
|
|
# Don't use self.class, MRI doesn't honor subclasses here
|
|
Time.specific(seconds - other_sec, nsec - other_nsec, @is_gmt, @offset)
|
|
end
|
|
|
|
def localtime(offset=nil)
|
|
@is_gmt = false
|
|
@offset = nil
|
|
@decomposed = nil
|
|
|
|
if offset
|
|
@offset = Rubinius::Type.coerce_to_utc_offset(offset)
|
|
@zone = nil
|
|
else
|
|
@offset = gmt_offset
|
|
@zone = Rubinius.invoke_primitive(:time_env_zone, self)
|
|
end
|
|
|
|
self
|
|
end
|
|
|
|
def getlocal(offset=nil)
|
|
dup.localtime(offset)
|
|
end
|
|
|
|
def eql?(other)
|
|
other.kind_of?(Time) and seconds == other.seconds and nsec == other.nsec
|
|
end
|
|
|
|
def <=>(other)
|
|
if other.kind_of? Time
|
|
(seconds <=> other.seconds).nonzero? or (nsec <=> other.nsec)
|
|
else
|
|
r = (other <=> self)
|
|
return nil if r == nil
|
|
return -1 if r > 0
|
|
return 1 if r < 0
|
|
0
|
|
end
|
|
end
|
|
|
|
#
|
|
# Rounds sub seconds to a given precision in decimal digits
|
|
#
|
|
# Returns a new time object.
|
|
#
|
|
# places should be nonnegative, it is 0 by default.
|
|
#
|
|
def round(places = 0)
|
|
return dup if nsec == 0
|
|
|
|
roundable_time = (to_i + subsec.to_r).round(places)
|
|
|
|
sec = roundable_time.floor
|
|
nano = ((roundable_time - sec) * 1_000_000_000).floor
|
|
|
|
Time.specific(sec, nano, @is_gmt, @offset)
|
|
end
|
|
|
|
class << self
|
|
def compose_deal_with_year(year)
|
|
year
|
|
end
|
|
private :compose_deal_with_year
|
|
end
|
|
|
|
#--
|
|
# TODO: doesn't load ivars
|
|
#++
|
|
|
|
def self._load(data)
|
|
raise TypeError, 'marshaled time format differ' unless data.bytesize == 8
|
|
|
|
major, minor = data.unpack 'VV'
|
|
|
|
if (major & (1 << 31)) == 0
|
|
at major, minor
|
|
else
|
|
major &= ~(1 << 31)
|
|
|
|
is_gmt = (major >> 30) & 0x1
|
|
year = ((major >> 14) & 0xffff) + 1900
|
|
mon = ((major >> 10) & 0xf) + 1
|
|
mday = (major >> 5) & 0x1f
|
|
hour = major & 0x1f
|
|
|
|
min = (minor >> 26) & 0x3f
|
|
sec = (minor >> 20) & 0x3f
|
|
isdst = false
|
|
|
|
usec = minor & 0xfffff
|
|
|
|
time = gm year, mon, mday, hour, min, sec, usec
|
|
time.localtime if is_gmt.zero?
|
|
time
|
|
end
|
|
end
|
|
|
|
class << self
|
|
private :_load
|
|
end
|
|
|
|
#--
|
|
# TODO: doesn't dump ivars
|
|
#++
|
|
|
|
def _dump(limit = nil)
|
|
tm = getgm.to_a
|
|
|
|
if (year & 0xffff) != year || year < 1900
|
|
raise ArgumentError, "year too big to marshal: #{year}"
|
|
end
|
|
|
|
gmt = @is_gmt ? 1 : 0
|
|
|
|
major = 1 << 31 | # 1 bit
|
|
gmt << 30 | # 1 bit
|
|
(tm[5] - 1900) << 14 | # 16 bits
|
|
(tm[4] - 1) << 10 | # 4 bits
|
|
tm[3] << 5 | # 5 bits
|
|
tm[2] # 5 bits
|
|
minor = tm[1] << 26 | # 6 bits
|
|
tm[0] << 20 | # 6 bits
|
|
usec # 20 bits
|
|
|
|
[major, minor].pack 'VV'
|
|
end
|
|
|
|
private :_dump
|
|
|
|
def self.compose(offset, p1, p2=nil, p3=nil, p4=nil, p5=nil, p6=nil, p7=nil,
|
|
yday=undefined, is_dst=undefined, tz=undefined)
|
|
if undefined.equal?(tz)
|
|
unless undefined.equal?(is_dst)
|
|
raise ArgumentError, "wrong number of arguments (9 for 1..8)"
|
|
end
|
|
|
|
y = p1
|
|
m = p2
|
|
d = p3
|
|
hr = p4
|
|
min = p5
|
|
sec = p6
|
|
usec = p7
|
|
is_dst = -1
|
|
else
|
|
y = p6
|
|
m = p5
|
|
d = p4
|
|
hr = p3
|
|
min = p2
|
|
sec = p1
|
|
usec = 0
|
|
is_dst = is_dst ? 1 : 0
|
|
end
|
|
|
|
if m.kind_of?(String) or m.respond_to?(:to_str)
|
|
m = StringValue(m)
|
|
m = MonthValue[m.upcase] || m.to_i
|
|
|
|
raise ArgumentError, "month argument out of range" unless m
|
|
else
|
|
m = Rubinius::Type.coerce_to(m || 1, Integer, :to_int)
|
|
end
|
|
|
|
y = y.kind_of?(String) ? y.to_i : Rubinius::Type.coerce_to(y, Integer, :to_int)
|
|
d = d.kind_of?(String) ? d.to_i : Rubinius::Type.coerce_to(d || 1, Integer, :to_int)
|
|
hr = hr.kind_of?(String) ? hr.to_i : Rubinius::Type.coerce_to(hr || 0, Integer, :to_int)
|
|
min = min.kind_of?(String) ? min.to_i : Rubinius::Type.coerce_to(min || 0, Integer, :to_int)
|
|
|
|
nsec = nil
|
|
|
|
if usec.kind_of?(String)
|
|
nsec = usec.to_i * 1000
|
|
elsif usec
|
|
nsec = (usec * 1000).to_i
|
|
end
|
|
|
|
y = compose_deal_with_year(y)
|
|
|
|
case offset
|
|
when :utc
|
|
is_dst = -1
|
|
is_utc = true
|
|
offset = nil
|
|
when :local
|
|
is_utc = false
|
|
offset = nil
|
|
else
|
|
is_dst = -1
|
|
is_utc = false
|
|
end
|
|
|
|
from_array(sec, min, hr, d, m, y, nsec, is_dst, is_utc, offset)
|
|
end
|
|
|
|
def self.local(*args)
|
|
compose(:local, *args)
|
|
end
|
|
|
|
def self.gm(*args)
|
|
compose(:utc, *args)
|
|
end
|
|
|
|
def succ
|
|
self + 1
|
|
end
|
|
|
|
def asctime
|
|
strftime("%a %b %e %H:%M:%S %Y")
|
|
end
|
|
|
|
def sec
|
|
to_a[0]
|
|
end
|
|
|
|
def min
|
|
to_a[1]
|
|
end
|
|
|
|
def hour
|
|
to_a[2]
|
|
end
|
|
|
|
def day
|
|
to_a[3]
|
|
end
|
|
|
|
def mon
|
|
to_a[4]
|
|
end
|
|
|
|
def year
|
|
to_a[5]
|
|
end
|
|
|
|
def wday
|
|
to_a[6]
|
|
end
|
|
|
|
def yday
|
|
to_a[7]
|
|
end
|
|
|
|
def dst?
|
|
to_a[8]
|
|
end
|
|
|
|
def zone
|
|
zone = to_a[9]
|
|
|
|
if zone && Encoding.default_internal
|
|
zone.encode Encoding.default_internal
|
|
else
|
|
zone
|
|
end
|
|
end
|
|
|
|
def gmt?
|
|
@is_gmt
|
|
end
|
|
|
|
alias_method :to_i, :seconds
|
|
|
|
def gmt_offset
|
|
Rubinius.primitive :time_utc_offset
|
|
raise PrimitiveFailure, "Time#gmt_offset primitive failed"
|
|
end
|
|
|
|
def gmtime
|
|
unless @is_gmt
|
|
@is_gmt = true
|
|
@offset = nil
|
|
@decomposed = nil
|
|
end
|
|
|
|
self
|
|
end
|
|
|
|
def getgm
|
|
dup.gmtime
|
|
end
|
|
|
|
def hash
|
|
seconds ^ usec
|
|
end
|
|
|
|
class << self
|
|
alias_method :mktime, :local
|
|
alias_method :utc, :gm
|
|
end
|
|
|
|
alias_method :utc?, :gmt?
|
|
alias_method :month, :mon
|
|
alias_method :ctime, :asctime
|
|
alias_method :mday, :day
|
|
alias_method :to_i, :seconds
|
|
alias_method :tv_sec, :seconds
|
|
alias_method :tv_usec, :usec
|
|
alias_method :utc, :gmtime
|
|
alias_method :isdst, :dst?
|
|
alias_method :utc_offset, :gmt_offset
|
|
alias_method :gmtoff, :gmt_offset
|
|
alias_method :getutc, :getgm
|
|
end
|