Time in ruby is a confusing maze of suckiness.
The Ruby
Time class doesn't include a method to convert a string into a Time object (like the C standard 'strptime'), despite having a Time.strftime function. What the?
It turns out that Time.parse and Time.strptime
do exist, but confusingly they aren't in the core class, but in a
separate library you have to require that overrides the class. WTF?
irb(main):001:0> Time.parse
NoMethodError: undefined method `parse' for Time:Class
from (irb):1
irb(main):002:0> require 'time'
=> true
irb(main):003:0> Time.parse
ArgumentError: wrong number of arguments (0 for 1)
from (irb):3:in `parse'
from (irb):3
So it seems that the best way to read a time from a file and compare it to the current time is the following, which gives you an answer in seconds:
irb(main):010:0> a=Time.parse('2011-01-10 12:34:00 UTC')
=> Mon Jan 10 12:34:00 UTC 2011
irb(main):012:0> b=Time.now.utc
=> Fri Dec 09 20:47:32 UTC 2011
irb(main):013:0> b-a
=> 28800812.788154
The only downside of this is that the library never fails, it tries really hard to give you a Time object back, to the point where it will just return the current time if the string is rubbish:
irb(main):027:0> Time.parse('asdfasdfas')
=> Fri Dec 09 14:02:40 -0800 2011
whereas DateTime is actually more sensible:
irb(main):028:0> DateTime.parse('asdfasdfas')
ArgumentError: invalid date
from /usr/lib/ruby/1.8/date.rb:1576:in `new_by_frags'
from /usr/lib/ruby/1.8/date.rb:1621:in `parse'
from (irb):28
from :0
So my final solution was:
begin
DateTime.parse(time_string)
rescue ArgumentError
return 'UNKNOWN'
end
earlier = Time.parse(time_string)
now = Time.now.utc
hours = (now-earlier)/3600
return hours
Read on for an attempt to do the same with DateTime, which is a terrible, terrible API.
DateTime has a simple way to ingest strings (and also has a strptime):
irb(main):015:0> require 'date'
=> false
irb(main):023:0> a=DateTime.parse('2011-12-09 00:00:00 UTC')
=> #
irb(main):024:0> puts a
2011-12-09T00:00:00+00:00
=> nil
But you can't take a difference between Time and DateTime:
irb(main):027:0> a=DateTime.parse('2011-12-01 00:00:00 UTC')
=> #
irb(main):028:0> b=Time.now
=> Fri Dec 09 12:10:40 -0800 2011
irb(main):029:0> b-a
TypeError: can't convert DateTime into Float
from (irb):29:in `-'
from (irb):29
from :0
Subtracting two DateTimes works but gives you an answer that is a rational number of days (?!):
irb(main):031:0> b-a
=> Rational(76394798789, 8640000000)
irb(main):032:0> c=b-a
=> Rational(76394798789, 8640000000)
irb(main):033:0> puts c
76394798789/8640000000
=> nil
irb(main):034:0> puts c.to_f
8.8419906005787
=> nil
Since a fractional number of days is pretty useless you can then convert this to an array of [hours,minutes,seconds,frac]:
irb(main):036:0> DateTime.day_fraction_to_time(c)
=> [212, 12, 27, Rational(98789, 8640000000)]
Why the subtraction doesn't return another type of time object is beyond me.