class Time

Public Class Methods

httpdate(date) click to toggle source

Parses date as an HTTP-date defined by RFC 2616 and converts it to a Time object.

ArgumentError is raised if date is not compliant with RFC 2616 or if the Time class cannot represent specified date.

See httpdate for more information on this format.

require 'time'

Time.httpdate("Thu, 06 Oct 2011 02:26:12 GMT")
#=> 2011-10-06 02:26:12 UTC

You must require ‘time’ to use this method.

# File time.rb, line 563
def httpdate(date)
  if date.match?(/\A\s*
      (?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\x20
      (\d{2})\x20
      (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\x20
      (\d{4})\x20
      (\d{2}):(\d{2}):(\d{2})\x20
      GMT
      \s*\z/ix)
    self.rfc2822(date).utc
  elsif /\A\s*
         (?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday),\x20
         (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d)\x20
         (\d\d):(\d\d):(\d\d)\x20
         GMT
         \s*\z/ix =~ date
    year = $3.to_i
    if year < 50
      year += 2000
    else
      year += 1900
    end
    self.utc(year, $2, $1.to_i, $4.to_i, $5.to_i, $6.to_i)
  elsif /\A\s*
         (?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\x20
         (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\x20
         (\d\d|\x20\d)\x20
         (\d\d):(\d\d):(\d\d)\x20
         (\d{4})
         \s*\z/ix =~ date
    self.utc($6.to_i, MonthValue[$1.upcase], $2.to_i,
             $3.to_i, $4.to_i, $5.to_i)
  else
    raise ArgumentError.new("not RFC 2616 compliant date: #{date.inspect}")
  end
end
iso8601(time)
Alias for: xmlschema
parse(date, now=self.now) { |year| ... } click to toggle source

Takes a string representation of a Time and attempts to parse it using a heuristic.

This method **does not** function as a validator. If the input string does not match valid formats strictly, you may get a cryptic result. Should consider to use ‘Time.strptime` instead of this method as possible.

require 'time'

Time.parse("2010-10-31") #=> 2010-10-31 00:00:00 -0500

Any missing pieces of the date are inferred based on the current date.

require 'time'

# assuming the current date is "2011-10-31"
Time.parse("12:00") #=> 2011-10-31 12:00:00 -0500

We can change the date used to infer our missing elements by passing a second object that responds to mon, day and year, such as Date, Time or DateTime. We can also use our own object.

require 'time'

class MyDate
  attr_reader :mon, :day, :year

  def initialize(mon, day, year)
    @mon, @day, @year = mon, day, year
  end
end

d  = Date.parse("2010-10-28")
t  = Time.parse("2010-10-29")
dt = DateTime.parse("2010-10-30")
md = MyDate.new(10,31,2010)

Time.parse("12:00", d)  #=> 2010-10-28 12:00:00 -0500
Time.parse("12:00", t)  #=> 2010-10-29 12:00:00 -0500
Time.parse("12:00", dt) #=> 2010-10-30 12:00:00 -0500
Time.parse("12:00", md) #=> 2010-10-31 12:00:00 -0500

If a block is given, the year described in date is converted by the block. This is specifically designed for handling two digit years. For example, if you wanted to treat all two digit years prior to 70 as the year 2000+ you could write this:

require 'time'

Time.parse("01-10-31") {|year| year + (year < 70 ? 2000 : 1900)}
#=> 2001-10-31 00:00:00 -0500
Time.parse("70-10-31") {|year| year + (year < 70 ? 2000 : 1900)}
#=> 1970-10-31 00:00:00 -0500

If the upper components of the given time are broken or missing, they are supplied with those of now. For the lower components, the minimum values (1 or 0) are assumed if broken or missing. For example:

require 'time'

# Suppose it is "Thu Nov 29 14:33:20 2001" now and
# your time zone is EST which is GMT-5.
now = Time.parse("Thu Nov 29 14:33:20 2001")
Time.parse("16:30", now)     #=> 2001-11-29 16:30:00 -0500
Time.parse("7/23", now)      #=> 2001-07-23 00:00:00 -0500
Time.parse("Aug 31", now)    #=> 2001-08-31 00:00:00 -0500
Time.parse("Aug 2000", now)  #=> 2000-08-01 00:00:00 -0500

Since there are numerous conflicts among locally defined time zone abbreviations all over the world, this method is not intended to understand all of them. For example, the abbreviation “CST” is used variously as:

-06:00 in America/Chicago,
-05:00 in America/Havana,
+08:00 in Asia/Harbin,
+09:30 in Australia/Darwin,
+10:30 in Australia/Adelaide,
etc.

Based on this fact, this method only understands the time zone abbreviations described in RFC 822 and the system time zone, in the order named. (i.e. a definition in RFC 822 overrides the system time zone definition.) The system time zone is taken from Time.local(year, 1, 1).zone and Time.local(year, 7, 1).zone. If the extracted time zone abbreviation does not match any of them, it is ignored and the given time is regarded as a local time.

ArgumentError is raised if Date._parse cannot extract information from date or if the Time class cannot represent specified date.

This method can be used as a fail-safe for other parsing methods as:

Time.rfc2822(date) rescue Time.parse(date)
Time.httpdate(date) rescue Time.parse(date)
Time.xmlschema(date) rescue Time.parse(date)

A failure of Time.parse should be checked, though.

You must require ‘time’ to use this method.

# File time.rb, line 378
def parse(date, now=self.now)
  comp = !block_given?
  d = Date._parse(date, comp)
  year = d[:year]
  year = yield(year) if year && !comp
  make_time(date, year, d[:yday], d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:sec_fraction], d[:zone], now)
end
rfc2822(date) click to toggle source

Parses date as date-time defined by RFC 2822 and converts it to a Time object. The format is identical to the date format defined by RFC 822 and updated by RFC 1123.

ArgumentError is raised if date is not compliant with RFC 2822 or if the Time class cannot represent specified date.

See rfc2822 for more information on this format.

require 'time'

Time.rfc2822("Wed, 05 Oct 2011 22:26:12 -0400")
#=> 2010-10-05 22:26:12 -0400

You must require ‘time’ to use this method.

# File time.rb, line 505
def rfc2822(date)
  if /\A\s*
      (?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*,\s*)?
      (\d{1,2})\s+
      (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+
      (\d{2,})\s+
      (\d{2})\s*
      :\s*(\d{2})\s*
      (?::\s*(\d{2}))?\s+
      ([+-]\d{4}|
       UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[A-IK-Z])/ix =~ date
    # Since RFC 2822 permit comments, the regexp has no right anchor.
    day = $1.to_i
    mon = MonthValue[$2.upcase]
    year = $3.to_i
    short_year_p = $3.length <= 3
    hour = $4.to_i
    min = $5.to_i
    sec = $6 ? $6.to_i : 0
    zone = $7

    if short_year_p
      # following year completion is compliant with RFC 2822.
      year = if year < 50
               2000 + year
             else
               1900 + year
             end
    end

    off = zone_offset(zone)
    year, mon, day, hour, min, sec =
      apply_offset(year, mon, day, hour, min, sec, off)
    t = self.utc(year, mon, day, hour, min, sec)
    force_zone!(t, zone, off)
    t
  else
    raise ArgumentError.new("not RFC 2822 compliant date: #{date.inspect}")
  end
end
Also aliased as: rfc822
rfc822(date)
Alias for: rfc2822
strptime(date, format, now=self.now) { |year| ... } click to toggle source

Works similar to parse except that instead of using a heuristic to detect the format of the input string, you provide a second argument that describes the format of the string.

If a block is given, the year described in date is converted by the block. For example:

Time.strptime(...) {|y| y < 100 ? (y >= 69 ? y + 1900 : y + 2000) : y}

Below is a list of the formatting options:

%a

The abbreviated weekday name (“Sun”)

%A

The full weekday name (“Sunday”)

%b

The abbreviated month name (“Jan”)

%B

The full month name (“January”)

%c

The preferred local date and time representation

%C

Century (20 in 2009)

%d

Day of the month (01..31)

%D

Date (%m/%d/%y)

%e

Day of the month, blank-padded ( 1..31)

%F

Equivalent to %Y-%m-%d (the ISO 8601 date format)

%g

The last two digits of the commercial year

%G

The week-based year according to ISO-8601 (week 1 starts on Monday and includes January 4)

%h

Equivalent to %b

%H

Hour of the day, 24-hour clock (00..23)

%I

Hour of the day, 12-hour clock (01..12)

%j

Day of the year (001..366)

%k

hour, 24-hour clock, blank-padded ( 0..23)

%l

hour, 12-hour clock, blank-padded ( 0..12)

%L

Millisecond of the second (000..999)

%m

Month of the year (01..12)

%M

Minute of the hour (00..59)

%n

Newline (n)

%N

Fractional seconds digits

%p

Meridian indicator (“AM” or “PM”)

%P

Meridian indicator (“am” or “pm”)

%r

time, 12-hour (same as %I:%M:%S %p)

%R

time, 24-hour (%H:%M)

%s

Number of seconds since 1970-01-01 00:00:00 UTC.

%S

Second of the minute (00..60)

%t

Tab character (t)

%T

time, 24-hour (%H:%M:%S)

%u

Day of the week as a decimal, Monday being 1. (1..7)

%U

Week number of the current year, starting with the first Sunday as the first day of the first week (00..53)

%v

VMS date (%e-%b-%Y)

%V

Week number of year according to ISO 8601 (01..53)

%W

Week number of the current year, starting with the first Monday as the first day of the first week (00..53)

%w

Day of the week (Sunday is 0, 0..6)

%x

Preferred representation for the date alone, no time

%X

Preferred representation for the time alone, no date

%y

Year without a century (00..99)

%Y

Year which may include century, if provided

%z

Time zone as hour offset from UTC (e.g. +0900)

%Z

Time zone name

%%

Literal “%” character

%+

date(1) (%a %b %e %H:%M:%S %Z %Y)

require 'time'

Time.strptime("2000-10-31", "%Y-%m-%d") #=> 2000-10-31 00:00:00 -0500

You must require ‘time’ to use this method.

# File time.rb, line 453
def strptime(date, format, now=self.now)
  d = Date._strptime(date, format)
  raise ArgumentError, "invalid date or strptime format - `#{date}' `#{format}'" unless d
  if seconds = d[:seconds]
    if sec_fraction = d[:sec_fraction]
      usec = sec_fraction * 1000000
      usec *= -1 if seconds < 0
    else
      usec = 0
    end
    t = Time.at(seconds, usec)
    if zone = d[:zone]
      force_zone!(t, zone)
    end
  else
    year = d[:year]
    year = yield(year) if year && block_given?
    yday = d[:yday]
    if (d[:cwyear] && !year) || ((d[:cwday] || d[:cweek]) && !(d[:mon] && d[:mday]))
      # make_time doesn't deal with cwyear/cwday/cweek
      return Date.strptime(date, format).to_time
    end
    if (d[:wnum0] || d[:wnum1]) && !yday && !(d[:mon] && d[:mday])
      yday = Date.strptime(date, format).yday
    end
    t = make_time(date, year, yday, d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:sec_fraction], d[:zone], now)
  end
  t
end
xmlschema(time) click to toggle source

Parses time as a dateTime defined by the XML Schema and converts it to a Time object. The format is a restricted version of the format defined by ISO 8601.

ArgumentError is raised if time is not compliant with the format or if the Time class cannot represent the specified time.

See xmlschema for more information on this format.

require 'time'

Time.xmlschema("2011-10-05T22:26:12-04:00")
#=> 2011-10-05 22:26:12-04:00

You must require ‘time’ to use this method.

# File time.rb, line 617
def xmlschema(time)
  if /\A\s*
      (-?\d+)-(\d\d)-(\d\d)
      T
      (\d\d):(\d\d):(\d\d)
      (\.\d+)?
      (Z|[+-]\d\d(?::?\d\d)?)?
      \s*\z/ix =~ time
    year = $1.to_i
    mon = $2.to_i
    day = $3.to_i
    hour = $4.to_i
    min = $5.to_i
    sec = $6.to_i
    usec = 0
    if $7
      usec = Rational($7) * 1000000
    end
    if $8
      zone = $8
      off = zone_offset(zone)
      year, mon, day, hour, min, sec =
        apply_offset(year, mon, day, hour, min, sec, off)
      t = self.utc(year, mon, day, hour, min, sec, usec)
      force_zone!(t, zone, off)
      t
    else
      self.local(year, mon, day, hour, min, sec, usec)
    end
  else
    raise ArgumentError.new("invalid xmlschema format: #{time.inspect}")
  end
end
Also aliased as: iso8601
zone_offset(zone, year=self.now.year) click to toggle source

Return the number of seconds the specified time zone differs from UTC.

Numeric time zones that include minutes, such as -10:00 or +1330 will work, as will simpler hour-only time zones like -10 or +13.

Textual time zones listed in ZoneOffset are also supported.

If the time zone does not match any of the above, zone_offset will check if the local time zone (both with and without potential Daylight Saving Time changes being in effect) matches zone. Specifying a value for year will change the year used to find the local time zone.

If zone_offset is unable to determine the offset, nil will be returned.

require 'time'

Time.zone_offset("EST") #=> -18000

You must require ‘time’ to use this method.

# File time.rb, line 79
def zone_offset(zone, year=self.now.year)
  off = nil
  zone = zone.upcase
  if /\A([+-])(\d\d)(:?)(\d\d)(?:\3(\d\d))?\z/ =~ zone
    off = ($1 == '-' ? -1 : 1) * (($2.to_i * 60 + $4.to_i) * 60 + $5.to_i)
  elsif zone.match?(/\A[+-]\d\d\z/)
    off = zone.to_i * 3600
  elsif ZoneOffset.include?(zone)
    off = ZoneOffset[zone] * 3600
  elsif ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false)
    off = t.utc_offset
  elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false)
    off = t.utc_offset
  end
  off
end

Public Instance Methods

httpdate() click to toggle source

Returns a string which represents the time as RFC 1123 date of HTTP-date defined by RFC 2616:

day-of-week, DD month-name CCYY hh:mm:ss GMT

Note that the result is always UTC (GMT).

require 'time'

t = Time.now
t.httpdate # => "Thu, 06 Oct 2011 02:26:12 GMT"

You must require ‘time’ to use this method.

# File time.rb, line 689
def httpdate
  getutc.strftime('%a, %d %b %Y %T GMT')
end
iso8601(fraction_digits=0)
Alias for: xmlschema
rfc2822() click to toggle source

Returns a string which represents the time as date-time defined by RFC 2822:

day-of-week, DD month-name CCYY hh:mm:ss zone

where zone is [+-]hhmm.

If self is a UTC time, -0000 is used as zone.

require 'time'

t = Time.now
t.rfc2822  # => "Wed, 05 Oct 2011 22:26:12 -0400"

You must require ‘time’ to use this method.

# File time.rb, line 669
def rfc2822
  strftime('%a, %d %b %Y %T ') << (utc? ? '-0000' : strftime('%z'))
end
Also aliased as: rfc822
rfc822()
Alias for: rfc2822
xmlschema(fraction_digits=0) click to toggle source

Returns a string which represents the time as a dateTime defined by XML Schema:

CCYY-MM-DDThh:mm:ssTZD
CCYY-MM-DDThh:mm:ss.sssTZD

where TZD is Z or [+-]hh:mm.

If self is a UTC time, Z is used as TZD. [+-]hh:mm is used otherwise.

fractional_digits specifies a number of digits to use for fractional seconds. Its default value is 0.

require 'time'

t = Time.now
t.iso8601  # => "2011-10-05T22:26:12-04:00"

You must require ‘time’ to use this method.

# File time.rb, line 714
def xmlschema(fraction_digits=0)
  fraction_digits = fraction_digits.to_i
  s = strftime("%FT%T")
  if fraction_digits > 0
    s << strftime(".%#{fraction_digits}N")
  end
  s << (utc? ? 'Z' : strftime("%:z"))
end
Also aliased as: iso8601