10.years
. However, when you scratch below the surface, it all becomes a bit mysterious. I put this into a view to investigate:<%
[1.seconds, 1.minutes, 1.hours, 1.days, 1.months, 1.years].each do |period|
%>
<ul>
<li><%="value=#{period}"%></li>
<li><%="inspect=#{period.inspect}"%></li>
<li><%="class=#{period.class}"%></li>
<li><%="Duration?=#{period.is_a?(ActiveSupport::Duration)}"%></li>
<li><%="to_i=#{period.to_i}"%></li>
<li><%="to_i.class=#{period.to_i.class}"%></li>
<li><%="to_i.inspect=#{period.to_i.inspect}"%></li>
</ul>
<% end %>
The output for seconds looked like this:
- value=1
- inspect=1 second
- class=Fixnum
- Duration?=true
- to_i=1
- to_i.class=Fixnum
- to_i.inspect=1
It would seem that what we are using here are
ActiveSupport::Duration
objects, which are pretending to be Fixnum
objects. Their value is the duration in seconds, but an inspect
will add the units, and for days, months and years will give the value in those units (but minutes and hours are given in seconds). I would guess the point here is to fool other methods into treating these objects as Fixnum
objects, while retaining the added functionality. Curiously, the years
method returns an object that pretends to be a Float
, even though it does admit to being an ActiveSupport::Duration
.By the way, each of these methods has a singular alias;
year
can be used instead of years
, etc.Something else a little odd here (I am multiply the first by 1.0 to convert to float arithmetic):
<p>Number of days in a month: <%= 1.0 * 1.months / 1.days %></p>
<p>Number of months in a year: <%= 1.years / 1.months %></p>
<p>Number of days in a year: <%= 1.years / 1.days %></p>
The result:
Number of days in a month: 30.0
Number of months in a year: 12.175
Number of days in a year: 365.25
So the Rails system quietly ignores anomolous leap years (the last was in 1900, the next in 2100 so is a reasonable approximation), but more bizarrely has slightly more than 12 months in a year. Would it not have made more sense to have 30.4375 days in a month?
Rails also introduces the ActiveSupport::TimeWithZone object. This is an object that "acts like" a Time object, but can handle different time zones.
The
created_at
and updated_at
fields of an ActiveRecord
return objects of this type. You can also convert an ActiveSupport::Duration
to an ActiveSupport::TimeWithZone
using ago
(and its alias since
) and from_now
(and its alias until
). Both these statements produce ActiveSupport::TimeWithZone objects:first_sample = Sample.find(:first).created_at
now = 0.seconds.ago
Arithmetic with ActiveSupport::TimeWithZone objects will give a
Float
object representing a number of seconds (surely an ActiveSupport::Duration
masquerading as a Float
would make more sense).elapsed = now - first_sample
You can use
ActiveSupport::TimeWithZone
objects in your database searches.# Find all samples changed in the last week
Sample.find :all :conditions => ["updated_at > ?", 1.week.ago]
# Count all samples created between 1 and 2 years ago.
Sample.count :conditions => ["created_at > ? AND created_at < ?", 2.years.ago, 1.year.ago]
See also:
http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Numeric/Time.html
Struggling with Ruby: Contents Page
1 comment:
good Work !!!
Post a Comment