DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Make Time "Stand Still" In Ruby

11.15.2007
| 6533 views |
  • submit to reddit
        When writing tests, it's sometimes difficult to test results of methods that use current time. Two calls to Time.now can give different results and cause test failures. Here is some code that lets you execute a block during which Time.now will return a consistent value:

class Time

  # this code adds a Time.freeze method to make time "stand still"
  # during execution of a block. This can be helpful during testing of
  # methods that depend on Time.new or Time.now
  #
  # Example:
  #
  #   Time.freeze do
  #      puts Time.new.to_f
  #      # ... do stuff; real time passes
  #      puts Time.new.to_f     # outputs same time as above
  #   end
  #   # ... time returns to normal
  #
  # An optional Time object may be passed to freeze to a specific time:
  #
  #   Time.freeze(Time.at(2007, 11, 15)) do
  #      # ...
  #   end
  #
  # While inside the block, Time.frozen? will return true

  class << self

    def now
      @time || orig_new
    end

    alias_method :orig_freeze, :freeze
    alias_method :orig_new, :new
    alias_method :new, :now

    # makes time "stand still" during execution of a block. if no time is
    # supplied, the current time is used. While in the block, Time.new and
    # Time.now will always return the "frozen" value.
    def freeze(time = nil)
      raise "A block is required" unless block_given?
      begin
        prev = @time
        @time = time || now
        yield
      ensure
        @time = prev
      end
    end

    def frozen?
      !@time.nil?
    end

  end
end