Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #6835: add-duration-to-date-time3.diff

File add-duration-to-date-time3.diff, 11.2 kB (added by eventualbuddha, 2 years ago)
  • activesupport/test/core_ext/numeric_ext_test.rb

    old new  
    3434      assert seconds.from_now >= now + seconds 
    3535    end 
    3636  end 
     37   
     38  def test_irregular_durations 
     39    assert_equal @now.advance(:days => 3000), 3000.days.since(@now) 
     40    assert_equal @now.advance(:months => 1), 1.month.since(@now) 
     41    assert_equal @now.advance(:months => -1), 1.month.until(@now) 
     42    assert_equal @now.advance(:years => 20), 20.years.since(@now) 
     43  end 
     44   
     45  def test_duration_addition 
     46    assert_equal @now.advance(:days => 1, :months => 1), (1.day + 1.month).since(@now) 
     47    assert_equal @now.advance(:days => 7), (1.week + 5.seconds - 5.seconds).since(@now) 
     48    assert_equal @now.advance(:years => 2), (4.years - 2.years).since(@now) 
     49  end 
     50   
     51  def test_time_plus_duration 
     52    assert_equal @now + 8, @now + 8.seconds 
     53    assert_equal @now + 22.9, @now + 22.9.seconds 
     54    assert_equal @now.advance(:days => 15), @now + 15.days 
     55    assert_equal @now.advance(:months => 1), @now + 1.month 
     56  end 
     57   
     58  def test_chaining_duration_operations 
     59    assert_equal @now.advance(:days => 2, :months => -3), @now + 2.days - 3.months 
     60    assert_equal @now.advance(:days => 1, :months => 2), @now + 1.day + 2.months 
     61  end 
     62   
     63  def test_duration_after_convertion_is_no_longer_accurate 
     64    assert_equal 30.days.to_i.since(@now), 1.month.to_i.since(@now) 
     65    assert_equal 365.25.days.to_f.since(@now), 1.year.to_f.since(@now) 
     66  end 
    3767end 
    3868 
     69class NumericExtDateTest < Test::Unit::TestCase 
     70  def setup 
     71    @today = Date.today 
     72  end 
     73 
     74  def test_date_plus_duration 
     75    assert_equal @today + 1, @today + 1.day 
     76    assert_equal @today >> 1, @today + 1.month 
     77    assert_raises(ArgumentError) { @today + 1.second } 
     78  end 
     79   
     80  def test_chaining_duration_operations 
     81    assert_equal @today.advance(:days => 2, :months => -3), @today + 2.days - 3.months 
     82    assert_equal @today.advance(:days => 1, :months => 2), @today + 1.day + 2.months 
     83  end 
     84end 
     85 
    3986class NumericExtSizeTest < Test::Unit::TestCase 
    4087  def test_unit_in_terms_of_another 
    4188    relationships = { 
  • activesupport/lib/active_support/duration.rb

    old new  
     1module ActiveSupport 
     2  class Duration < Builder::BlankSlate 
     3    attr_accessor :value, :parts 
     4     
     5    def initialize(value, parts) 
     6      @value, @parts = value, parts 
     7    end 
     8     
     9    def +(other) 
     10      if Duration === other 
     11        Duration.new(value + other.value, @parts + other.parts) 
     12      else 
     13        Duration.new(value + other, @parts + [[:seconds, other]]) 
     14      end 
     15    end 
     16     
     17    def -(other) 
     18      self + (-other) 
     19    end 
     20     
     21    def -@ 
     22      Duration.new(-value, parts.map { |type,number| [type, -number] }) 
     23    end 
     24     
     25    def is_a?(klass) 
     26      klass == Duration || super 
     27    end 
     28     
     29    def self.===(other) 
     30      other.is_a?(Duration) rescue super 
     31    end 
     32     
     33    def since(time = ::Time.now) 
     34      sum(1, time) 
     35    end 
     36    alias :from_now :since 
     37     
     38    def ago(time = ::Time.now) 
     39      sum(-1, time) 
     40    end 
     41    alias :until :ago 
     42     
     43    def inspect 
     44      "(#{value}, #{parts.inspect})" 
     45    end 
     46     
     47    protected 
     48     
     49    def sum(sign, time = ::Time.now) 
     50      parts.inject(time) do |t,(type,number)| 
     51        case t 
     52        when ::Time 
     53          if type == :seconds 
     54            t + (sign * number) 
     55          else 
     56            t.advance(type => sign * number) 
     57          end 
     58        when ::Date 
     59          raise ArgumentError, "Adding seconds to a Date does not make sense" if type == :seconds 
     60          t.advance(type => sign * number) 
     61        end 
     62      end 
     63    end 
     64     
     65    private 
     66     
     67    def method_missing(method, *args, &block) 
     68      value.send(method, *args) 
     69    end 
     70  end 
     71end 
  • activesupport/lib/active_support/core_ext/time/calculations.rb

    old new  
    55      module Calculations 
    66        def self.included(base) #:nodoc: 
    77          base.extend(ClassMethods) 
     8           
     9          base.send(:alias_method, :plus_without_duration, :+) 
     10          base.send(:alias_method, :+, :plus_with_duration) 
     11          base.send(:alias_method, :minus_without_duration, :-) 
     12          base.send(:alias_method, :-, :minus_with_duration) 
    813        end 
    914 
    1015        module ClassMethods 
     
    190195        def tomorrow 
    191196          self.since(1.day) 
    192197        end 
     198         
     199        def plus_with_duration(other) #:nodoc: 
     200          if ActiveSupport::Duration === other 
     201            other.since(self) 
     202          else 
     203            plus_without_duration(other) 
     204          end 
     205        end 
     206 
     207        def minus_with_duration(other) #:nodoc: 
     208          if ActiveSupport::Duration === other 
     209            other.until(self) 
     210          else 
     211            minus_without_duration(other) 
     212          end 
     213        end 
    193214      end 
    194215    end 
    195216  end 
  • activesupport/lib/active_support/core_ext/numeric/time.rb

    old new  
    33    module Numeric #:nodoc: 
    44      # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years. 
    55      # 
    6       # If you need precise date calculations that doesn't just treat months as 30 days, then have 
    7       # a look at Time#advance. 
     6      # These methods use Time#advance for precise date calculations when using from_now, ago, etc.  
     7      # as well as adding or subtracting their results from a Time object. For example: 
     8      # 
     9      #   # equivalent to Time.now.advance(:months => 1) 
     10      #   1.month.from_now 
     11      # 
     12      #   # equivalent to Time.now.advance(:years => 2) 
     13      #   2.years.from_now 
     14      # 
     15      #   # equivalent to Time.now.advance(:months => 4, :years => 5) 
     16      #   (4.months + 5.years).from_now 
    817      #  
    9       # Some of these methods are approximations, Ruby's core  
     18      # While these methods provide precise calculation when used as in the examples above, care 
     19      # should be taken to note that this is not true if the result of `months', `years', etc is 
     20      # converted before use: 
     21      # 
     22      #   # equivalent to 30.days.to_i.from_now 
     23      #   1.month.to_i.from_now 
     24      # 
     25      #   # equivalent to 365.25.days.to_f.from_now 
     26      #   1.year.to_f.from_now 
     27      # 
     28      # In such cases, Ruby's core  
    1029      # Date[http://stdlib.rubyonrails.org/libdoc/date/rdoc/index.html] and  
    1130      # Time[http://stdlib.rubyonrails.org/libdoc/time/rdoc/index.html] should be used for precision 
    1231      # date and time arithmetic 
    1332      module Time 
    1433        def seconds 
    15           self 
     34          ActiveSupport::Duration.new(self, [[:seconds, self]]) 
    1635        end 
    1736        alias :second :seconds 
    1837 
    1938        def minutes 
    20           self * 60 
     39          ActiveSupport::Duration.new(self * 60, [[:seconds, self * 60]]) 
    2140        end 
    2241        alias :minute :minutes   
    2342         
    2443        def hours 
    25           self * 60.minutes 
     44          ActiveSupport::Duration.new(self * 3600, [[:seconds, self * 3600]]) 
    2645        end 
    2746        alias :hour :hours 
    2847         
    2948        def days 
    30           self * 24.hours 
     49          ActiveSupport::Duration.new(self * 24.hours, [[:days, self]]) 
    3150        end 
    3251        alias :day :days 
    3352 
    3453        def weeks 
    35           self * 7.days 
     54          ActiveSupport::Duration.new(self * 7.days, [[:days, self * 7]]) 
    3655        end 
    3756        alias :week :weeks 
    3857         
    3958        def fortnights 
    40           self * 2.weeks 
     59          ActiveSupport::Duration.new(self * 2.weeks, [[:days, self * 14]]) 
    4160        end 
    4261        alias :fortnight :fortnights 
    4362         
    4463        def months 
    45           self * 30.days 
     64          ActiveSupport::Duration.new(self * 30.days, [[:months, self]]) 
    4665        end 
    4766        alias :month :months 
    4867 
    4968        def years 
    50           (self * 365.25.days).to_i 
     69          ActiveSupport::Duration.new(self * 365.25.days, [[:years, self]]) 
    5170        end 
    5271        alias :year :years 
    5372 
  • activesupport/lib/active_support/core_ext/date/calculations.rb

    old new  
     1module ActiveSupport #:nodoc: 
     2  module CoreExtensions #:nodoc: 
     3    module Date #:nodoc: 
     4      # Enables the use of time calculations within Time itself 
     5      module Calculations 
     6        def self.included(base) #:nodoc: 
     7          base.send(:include, ClassMethods) 
     8           
     9          base.send(:alias_method, :plus_without_duration, :+) 
     10          base.send(:alias_method, :+, :plus_with_duration) 
     11           
     12          base.send(:alias_method, :minus_without_duration, :-) 
     13          base.send(:alias_method, :-, :minus_with_duration) 
     14        end 
     15 
     16        module ClassMethods 
     17          def plus_with_duration(other) 
     18            if ActiveSupport::Duration === other 
     19              other.since(self) 
     20            else 
     21              plus_without_duration(other) 
     22            end 
     23          end 
     24           
     25          def minus_with_duration(other) 
     26            self.plus_with_duration(-other) 
     27          end 
     28 
     29          def advance(options) 
     30            d = ::Date.new(year + (options.delete(:years) || 0), month, day) 
     31            d = d >> options.delete(:months) if options[:months] 
     32            d = d + options.delete(:days) if options[:days] 
     33            d 
     34          end 
     35        end 
     36      end 
     37    end 
     38  end 
     39end 
  • activesupport/lib/active_support/core_ext/date.rb

    old new  
    11require 'date' 
     2require File.dirname(__FILE__) + '/date/calculations' 
    23require File.dirname(__FILE__) + '/date/conversions' 
    34 
    45class Date#:nodoc: 
     6  include ActiveSupport::CoreExtensions::Date::Calculations 
    57  include ActiveSupport::CoreExtensions::Date::Conversions 
    68end 
  • activesupport/lib/active_support.rb

    old new  
    3838require 'active_support/option_merger' 
    3939 
    4040require 'active_support/values/time_zone' 
     41require 'active_support/duration' 
    4142 
    4243require 'active_support/json'