Problem
Given a point in time, you want to get somewhere else.
Solution
All of Ruby's time objects can be used in ranges as though they were numbers. Date and DateTime objects iterate in increments of one day, and Time objects iterate in increments of one second:
require 'date' (Date.new(1776, 7, 2)..Date.new(1776, 7, 4)).each { |x| puts x } # 1776-07-02 # 1776-07-03 # 1776-07-04 span = DateTime.new(1776, 7, 2, 1, 30, 15)..DateTime.new(1776, 7, 4, 7, 0, 0) span.each { |x| puts x } # 1776-07-02T01:30:15Z # 1776-07-03T01:30:15Z # 1776-07-04T01:30:15Z (Time.at(100)..Time.at(102)).each { |x| puts x } # Wed Dec 31 19:01:40 EST 1969 # Wed Dec 31 19:01:41 EST 1969 # Wed Dec 31 19:01:42 EST 1969
Ruby's Date class defines step and upto, the same convenient iterator methods used by numbers:
the_first = Date.new(2004, 1, 1) the_fifth = Date.new(2004, 1, 5) the_first.upto(the_fifth) { |x| puts x } # 2004-01-01 # 2004-01-02 # 2004-01-03 # 2004-01-04 # 2004-01-05
Discussion
Ruby date objects are stored internally as numbers, and a range of those objects is treated like a range of numbers. For Date and DateTime objects, the internal representation is the Julian day: iterating over a range of those objects adds one day at a time. For Time objects, the internal representation is the number of seconds since the Unix epoch: iterating over a range of Time objects adds one second at a time.
Time doesn't define the step and upto method, but it's simple to add them:
class Time def step(other_time, increment) raise ArgumentError, "step can't be 0" if increment == 0 increasing = self < other_time if (increasing && increment < 0) || (!increasing && increment > 0) yield self return end d = self begin yield d d += increment end while (increasing ? d <= other_time : d >= other_time) end def upto(other_time) step(other_time, 1) { |x| yield x } end end the_first = Time.local(2004, 1, 1) the_second = Time.local(2004, 1, 2) the_first.step(the_second, 60 * 60 * 6) { |x| puts x } # Thu Jan 01 00:00:00 EST 2004 # Thu Jan 01 06:00:00 EST 2004 # Thu Jan 01 12:00:00 EST 2004 # Thu Jan 01 18:00:00 EST 2004 # Fri Jan 02 00:00:00 EST 2004 the_first.upto(the_first) { |x| puts x } # Thu Jan 01 00:00:00 EST 2004
See Also
Strings
Numbers
Date and Time
Arrays
Hashes
Files and Directories
Code Blocks and Iteration
Objects and Classes8
Modules and Namespaces
Reflection and Metaprogramming
XML and HTML
Graphics and Other File Formats
Databases and Persistence
Internet Services
Web Development Ruby on Rails
Web Services and Distributed Programming
Testing, Debugging, Optimizing, and Documenting
Packaging and Distributing Software
Automating Tasks with Rake
Multitasking and Multithreading
User Interface
Extending Ruby with Other Languages
System Administration