diff options
author | Jeremy Kemper <jeremy@bitsweat.net> | 2009-03-28 23:45:34 -0700 |
---|---|---|
committer | Jeremy Kemper <jeremy@bitsweat.net> | 2009-03-28 23:45:34 -0700 |
commit | 092b5d125c328bcc0afec01ecc50a4388606ffeb (patch) | |
tree | e253085b947d8b864326f74538c33cf216fedc78 /activesupport/lib | |
parent | 609c1988d2e274b365c5299cc5933fb6855e4175 (diff) | |
download | rails-092b5d125c328bcc0afec01ecc50a4388606ffeb.tar.gz rails-092b5d125c328bcc0afec01ecc50a4388606ffeb.tar.bz2 rails-092b5d125c328bcc0afec01ecc50a4388606ffeb.zip |
Convert Date calculations and conversions extension modules to class reopens
Diffstat (limited to 'activesupport/lib')
3 files changed, 302 insertions, 325 deletions
diff --git a/activesupport/lib/active_support/core_ext/date.rb b/activesupport/lib/active_support/core_ext/date.rb index ebc333b7f7..6672129076 100644 --- a/activesupport/lib/active_support/core_ext/date.rb +++ b/activesupport/lib/active_support/core_ext/date.rb @@ -1,5 +1,7 @@ -require 'active_support/core_ext/util' require 'date' + require 'active_support/core_ext/date/acts_like' require 'active_support/core_ext/date/freeze' -ActiveSupport.core_ext Date, %w(calculations conversions) + +require 'active_support/core_ext/date/calculations' +require 'active_support/core_ext/date/conversions' diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb index 7f94da015b..59efdbd1b6 100644 --- a/activesupport/lib/active_support/core_ext/date/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date/calculations.rb @@ -1,230 +1,215 @@ -module ActiveSupport #:nodoc: - module CoreExtensions #:nodoc: - module Date #:nodoc: - # Enables the use of time calculations within Date itself - module Calculations - def self.included(base) #:nodoc: - base.extend ClassMethods - - base.instance_eval do - alias_method :plus_without_duration, :+ - alias_method :+, :plus_with_duration - - alias_method :minus_without_duration, :- - alias_method :-, :minus_with_duration - end - end - - module ClassMethods - # Returns a new Date representing the date 1 day ago (i.e. yesterday's date). - def yesterday - ::Date.today.yesterday - end - - # Returns a new Date representing the date 1 day after today (i.e. tomorrow's date). - def tomorrow - ::Date.today.tomorrow - end - - # Returns Time.zone.today when config.time_zone is set, otherwise just returns Date.today. - def current - ::Time.zone_default ? ::Time.zone.today : ::Date.today - end - end - - # Tells whether the Date object's date lies in the past - def past? - self < ::Date.current - end - - # Tells whether the Date object's date is today - def today? - self.to_date == ::Date.current # we need the to_date because of DateTime - end - - # Tells whether the Date object's date lies in the future - def future? - self > ::Date.current - end - - # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00) - # and then subtracts the specified number of seconds - def ago(seconds) - to_time.since(-seconds) - end - - # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00) - # and then adds the specified number of seconds - def since(seconds) - to_time.since(seconds) - end - alias :in :since - - # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00) - def beginning_of_day - to_time - end - alias :midnight :beginning_of_day - alias :at_midnight :beginning_of_day - alias :at_beginning_of_day :beginning_of_day - - # Converts Date to a Time (or DateTime if necessary) with the time portion set to the end of the day (23:59:59) - def end_of_day - to_time.end_of_day - end - - def plus_with_duration(other) #:nodoc: - if ActiveSupport::Duration === other - other.since(self) - else - plus_without_duration(other) - end - end - - def minus_with_duration(other) #:nodoc: - if ActiveSupport::Duration === other - plus_with_duration(-other) - else - minus_without_duration(other) - end - end - - # Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with - # any of these keys: <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>. - def advance(options) - d = self - d = d >> options.delete(:years) * 12 if options[:years] - d = d >> options.delete(:months) if options[:months] - d = d + options.delete(:weeks) * 7 if options[:weeks] - d = d + options.delete(:days) if options[:days] - d - end - - # Returns a new Date where one or more of the elements have been changed according to the +options+ parameter. - # - # Examples: - # - # Date.new(2007, 5, 12).change(:day => 1) # => Date.new(2007, 5, 1) - # Date.new(2007, 5, 12).change(:year => 2005, :month => 1) # => Date.new(2005, 1, 12) - def change(options) - ::Date.new( - options[:year] || self.year, - options[:month] || self.month, - options[:day] || self.day - ) - end - - # Returns a new Date/DateTime representing the time a number of specified months ago - def months_ago(months) - advance(:months => -months) - end - - # Returns a new Date/DateTime representing the time a number of specified months in the future - def months_since(months) - advance(:months => months) - end - - # Returns a new Date/DateTime representing the time a number of specified years ago - def years_ago(years) - advance(:years => -years) - end - - # Returns a new Date/DateTime representing the time a number of specified years in the future - def years_since(years) - advance(:years => years) - end - - # Short-hand for years_ago(1) - def last_year - years_ago(1) - end - - # Short-hand for years_since(1) - def next_year - years_since(1) - end - - # Short-hand for months_ago(1) - def last_month - months_ago(1) - end - - # Short-hand for months_since(1) - def next_month - months_since(1) - end - - # Returns a new Date/DateTime representing the "start" of this week (i.e, Monday; DateTime objects will have time set to 0:00) - def beginning_of_week - days_to_monday = self.wday!=0 ? self.wday-1 : 6 - result = self - days_to_monday - self.acts_like?(:time) ? result.midnight : result - end - alias :monday :beginning_of_week - alias :at_beginning_of_week :beginning_of_week - - # Returns a new Date/DateTime representing the end of this week (Sunday, DateTime objects will have time set to 23:59:59) - def end_of_week - days_to_sunday = self.wday!=0 ? 7-self.wday : 0 - result = self + days_to_sunday.days - self.acts_like?(:time) ? result.end_of_day : result - end - alias :at_end_of_week :end_of_week - - # Returns a new Date/DateTime representing the start of the given day in next week (default is Monday). - def next_week(day = :monday) - days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6} - result = (self + 7).beginning_of_week + days_into_week[day] - self.acts_like?(:time) ? result.change(:hour => 0) : result - end - - # Returns a new ; DateTime objects will have time set to 0:00DateTime representing the start of the month (1st of the month; DateTime objects will have time set to 0:00) - def beginning_of_month - self.acts_like?(:time) ? change(:day => 1,:hour => 0, :min => 0, :sec => 0) : change(:day => 1) - end - alias :at_beginning_of_month :beginning_of_month - - # Returns a new Date/DateTime representing the end of the month (last day of the month; DateTime objects will have time set to 0:00) - def end_of_month - last_day = ::Time.days_in_month( self.month, self.year ) - self.acts_like?(:time) ? change(:day => last_day, :hour => 23, :min => 59, :sec => 59) : change(:day => last_day) - end - alias :at_end_of_month :end_of_month - - # Returns a new Date/DateTime representing the start of the quarter (1st of january, april, july, october; DateTime objects will have time set to 0:00) - def beginning_of_quarter - beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= self.month }) - end - alias :at_beginning_of_quarter :beginning_of_quarter - - # Returns a new Date/DateTime representing the end of the quarter (last day of march, june, september, december; DateTime objects will have time set to 23:59:59) - def end_of_quarter - beginning_of_month.change(:month => [3, 6, 9, 12].detect { |m| m >= self.month }).end_of_month - end - alias :at_end_of_quarter :end_of_quarter - - # Returns a new Date/DateTime representing the start of the year (1st of january; DateTime objects will have time set to 0:00) - def beginning_of_year - self.acts_like?(:time) ? change(:month => 1, :day => 1, :hour => 0, :min => 0, :sec => 0) : change(:month => 1, :day => 1) - end - alias :at_beginning_of_year :beginning_of_year - - # Returns a new Time representing the end of the year (31st of december; DateTime objects will have time set to 23:59:59) - def end_of_year - self.acts_like?(:time) ? change(:month => 12,:day => 31,:hour => 23, :min => 59, :sec => 59) : change(:month => 12, :day => 31) - end - alias :at_end_of_year :end_of_year - - # Convenience method which returns a new Date/DateTime representing the time 1 day ago - def yesterday - self - 1 - end - - # Convenience method which returns a new Date/DateTime representing the time 1 day since the instance time - def tomorrow - self + 1 - end - end +class Date + class << self + # Returns a new Date representing the date 1 day ago (i.e. yesterday's date). + def yesterday + ::Date.today.yesterday end + + # Returns a new Date representing the date 1 day after today (i.e. tomorrow's date). + def tomorrow + ::Date.today.tomorrow + end + + # Returns Time.zone.today when config.time_zone is set, otherwise just returns Date.today. + def current + ::Time.zone_default ? ::Time.zone.today : ::Date.today + end + end + + # Tells whether the Date object's date lies in the past + def past? + self < ::Date.current + end + + # Tells whether the Date object's date is today + def today? + self.to_date == ::Date.current # we need the to_date because of DateTime + end + + # Tells whether the Date object's date lies in the future + def future? + self > ::Date.current + end + + # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00) + # and then subtracts the specified number of seconds + def ago(seconds) + to_time.since(-seconds) + end + + # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00) + # and then adds the specified number of seconds + def since(seconds) + to_time.since(seconds) + end + alias :in :since + + # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00) + def beginning_of_day + to_time + end + alias :midnight :beginning_of_day + alias :at_midnight :beginning_of_day + alias :at_beginning_of_day :beginning_of_day + + # Converts Date to a Time (or DateTime if necessary) with the time portion set to the end of the day (23:59:59) + def end_of_day + to_time.end_of_day + end + + def plus_with_duration(other) #:nodoc: + if ActiveSupport::Duration === other + other.since(self) + else + plus_without_duration(other) + end + end + alias_method :plus_without_duration, :+ + alias_method :+, :plus_with_duration + + def minus_with_duration(other) #:nodoc: + if ActiveSupport::Duration === other + plus_with_duration(-other) + else + minus_without_duration(other) + end + end + alias_method :minus_without_duration, :- + alias_method :-, :minus_with_duration + + # Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with + # any of these keys: <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>. + def advance(options) + d = self + d = d >> options.delete(:years) * 12 if options[:years] + d = d >> options.delete(:months) if options[:months] + d = d + options.delete(:weeks) * 7 if options[:weeks] + d = d + options.delete(:days) if options[:days] + d + end + + # Returns a new Date where one or more of the elements have been changed according to the +options+ parameter. + # + # Examples: + # + # Date.new(2007, 5, 12).change(:day => 1) # => Date.new(2007, 5, 1) + # Date.new(2007, 5, 12).change(:year => 2005, :month => 1) # => Date.new(2005, 1, 12) + def change(options) + ::Date.new( + options[:year] || self.year, + options[:month] || self.month, + options[:day] || self.day + ) + end + + # Returns a new Date/DateTime representing the time a number of specified months ago + def months_ago(months) + advance(:months => -months) + end + + # Returns a new Date/DateTime representing the time a number of specified months in the future + def months_since(months) + advance(:months => months) + end + + # Returns a new Date/DateTime representing the time a number of specified years ago + def years_ago(years) + advance(:years => -years) + end + + # Returns a new Date/DateTime representing the time a number of specified years in the future + def years_since(years) + advance(:years => years) + end + + # Short-hand for years_ago(1) + def last_year + years_ago(1) + end + + # Short-hand for years_since(1) + def next_year + years_since(1) + end + + # Short-hand for months_ago(1) + def last_month + months_ago(1) + end + + # Short-hand for months_since(1) + def next_month + months_since(1) + end + + # Returns a new Date/DateTime representing the "start" of this week (i.e, Monday; DateTime objects will have time set to 0:00) + def beginning_of_week + days_to_monday = self.wday!=0 ? self.wday-1 : 6 + result = self - days_to_monday + self.acts_like?(:time) ? result.midnight : result + end + alias :monday :beginning_of_week + alias :at_beginning_of_week :beginning_of_week + + # Returns a new Date/DateTime representing the end of this week (Sunday, DateTime objects will have time set to 23:59:59) + def end_of_week + days_to_sunday = self.wday!=0 ? 7-self.wday : 0 + result = self + days_to_sunday.days + self.acts_like?(:time) ? result.end_of_day : result + end + alias :at_end_of_week :end_of_week + + # Returns a new Date/DateTime representing the start of the given day in next week (default is Monday). + def next_week(day = :monday) + days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6} + result = (self + 7).beginning_of_week + days_into_week[day] + self.acts_like?(:time) ? result.change(:hour => 0) : result + end + + # Returns a new ; DateTime objects will have time set to 0:00DateTime representing the start of the month (1st of the month; DateTime objects will have time set to 0:00) + def beginning_of_month + self.acts_like?(:time) ? change(:day => 1,:hour => 0, :min => 0, :sec => 0) : change(:day => 1) + end + alias :at_beginning_of_month :beginning_of_month + + # Returns a new Date/DateTime representing the end of the month (last day of the month; DateTime objects will have time set to 0:00) + def end_of_month + last_day = ::Time.days_in_month( self.month, self.year ) + self.acts_like?(:time) ? change(:day => last_day, :hour => 23, :min => 59, :sec => 59) : change(:day => last_day) + end + alias :at_end_of_month :end_of_month + + # Returns a new Date/DateTime representing the start of the quarter (1st of january, april, july, october; DateTime objects will have time set to 0:00) + def beginning_of_quarter + beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= self.month }) + end + alias :at_beginning_of_quarter :beginning_of_quarter + + # Returns a new Date/DateTime representing the end of the quarter (last day of march, june, september, december; DateTime objects will have time set to 23:59:59) + def end_of_quarter + beginning_of_month.change(:month => [3, 6, 9, 12].detect { |m| m >= self.month }).end_of_month + end + alias :at_end_of_quarter :end_of_quarter + + # Returns a new Date/DateTime representing the start of the year (1st of january; DateTime objects will have time set to 0:00) + def beginning_of_year + self.acts_like?(:time) ? change(:month => 1, :day => 1, :hour => 0, :min => 0, :sec => 0) : change(:month => 1, :day => 1) + end + alias :at_beginning_of_year :beginning_of_year + + # Returns a new Time representing the end of the year (31st of december; DateTime objects will have time set to 23:59:59) + def end_of_year + self.acts_like?(:time) ? change(:month => 12,:day => 31,:hour => 23, :min => 59, :sec => 59) : change(:month => 12, :day => 31) + end + alias :at_end_of_year :end_of_year + + # Convenience method which returns a new Date/DateTime representing the time 1 day ago + def yesterday + self - 1 + end + + # Convenience method which returns a new Date/DateTime representing the time 1 day since the instance time + def tomorrow + self + 1 end end diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb index 8d9f023361..f6c870035b 100644 --- a/activesupport/lib/active_support/core_ext/date/conversions.rb +++ b/activesupport/lib/active_support/core_ext/date/conversions.rb @@ -1,107 +1,97 @@ -module ActiveSupport #:nodoc: - module CoreExtensions #:nodoc: - module Date #:nodoc: - # Converting dates to formatted strings, times, and datetimes. - module Conversions - DATE_FORMATS = { - :short => "%e %b", - :long => "%B %e, %Y", - :db => "%Y-%m-%d", - :number => "%Y%m%d", - :long_ordinal => lambda { |date| date.strftime("%B #{date.day.ordinalize}, %Y") }, # => "April 25th, 2007" - :rfc822 => "%e %b %Y" - } +require 'active_support/inflector' - def self.included(base) #:nodoc: - base.instance_eval do - alias_method :to_default_s, :to_s - alias_method :to_s, :to_formatted_s - alias_method :default_inspect, :inspect - alias_method :inspect, :readable_inspect +class Date + DATE_FORMATS = { + :short => "%e %b", + :long => "%B %e, %Y", + :db => "%Y-%m-%d", + :number => "%Y%m%d", + :long_ordinal => lambda { |date| date.strftime("%B #{ActiveSupport::Inflector.ordinalize(date.day)}, %Y") }, # => "April 25th, 2007" + :rfc822 => "%e %b %Y" + } - # Ruby 1.9 has Date#to_time which converts to localtime only. - remove_method :to_time if base.instance_methods.include?(:to_time) + # Ruby 1.9 has Date#to_time which converts to localtime only. + remove_method :to_time if instance_methods.include?(:to_time) - # Ruby 1.9 has Date#xmlschema which converts to a string without the time component. - remove_method :xmlschema if base.instance_methods.include?(:xmlschema) - end - end + # Ruby 1.9 has Date#xmlschema which converts to a string without the time component. + remove_method :xmlschema if instance_methods.include?(:xmlschema) - # Convert to a formatted string. See DATE_FORMATS for predefined formats. - # - # This method is aliased to <tt>to_s</tt>. - # - # ==== Examples - # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007 - # - # date.to_formatted_s(:db) # => "2007-11-10" - # date.to_s(:db) # => "2007-11-10" - # - # date.to_formatted_s(:short) # => "10 Nov" - # date.to_formatted_s(:long) # => "November 10, 2007" - # date.to_formatted_s(:long_ordinal) # => "November 10th, 2007" - # date.to_formatted_s(:rfc822) # => "10 Nov 2007" - # - # == Adding your own time formats to to_formatted_s - # You can add your own formats to the Date::DATE_FORMATS hash. - # Use the format name as the hash key and either a strftime string - # or Proc instance that takes a date argument as the value. - # - # # config/initializers/time_formats.rb - # Date::DATE_FORMATS[:month_and_year] = "%B %Y" - # Date::DATE_FORMATS[:short_ordinal] = lambda { |date| date.strftime("%B #{date.day.ordinalize}") } - def to_formatted_s(format = :default) - if formatter = DATE_FORMATS[format] - if formatter.respond_to?(:call) - formatter.call(self).to_s - else - strftime(formatter) - end - else - to_default_s - end - end + # Convert to a formatted string. See DATE_FORMATS for predefined formats. + # + # This method is aliased to <tt>to_s</tt>. + # + # ==== Examples + # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007 + # + # date.to_formatted_s(:db) # => "2007-11-10" + # date.to_s(:db) # => "2007-11-10" + # + # date.to_formatted_s(:short) # => "10 Nov" + # date.to_formatted_s(:long) # => "November 10, 2007" + # date.to_formatted_s(:long_ordinal) # => "November 10th, 2007" + # date.to_formatted_s(:rfc822) # => "10 Nov 2007" + # + # == Adding your own time formats to to_formatted_s + # You can add your own formats to the Date::DATE_FORMATS hash. + # Use the format name as the hash key and either a strftime string + # or Proc instance that takes a date argument as the value. + # + # # config/initializers/time_formats.rb + # Date::DATE_FORMATS[:month_and_year] = "%B %Y" + # Date::DATE_FORMATS[:short_ordinal] = lambda { |date| date.strftime("%B #{date.day.ordinalize}") } + def to_formatted_s(format = :default) + if formatter = DATE_FORMATS[format] + if formatter.respond_to?(:call) + formatter.call(self).to_s + else + strftime(formatter) + end + else + to_default_s + end + end + alias_method :to_default_s, :to_s + alias_method :to_s, :to_formatted_s - # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005" - def readable_inspect - strftime("%a, %d %b %Y") - end + # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005" + def readable_inspect + strftime("%a, %d %b %Y") + end + alias_method :default_inspect, :inspect + alias_method :inspect, :readable_inspect - # A method to keep Time, Date and DateTime instances interchangeable on conversions. - # In this case, it simply returns +self+. - def to_date - self - end if RUBY_VERSION < '1.9' + # A method to keep Time, Date and DateTime instances interchangeable on conversions. + # In this case, it simply returns +self+. + def to_date + self + end if RUBY_VERSION < '1.9' - # Converts a Date instance to a Time, where the time is set to the beginning of the day. - # The timezone can be either :local or :utc (default :local). - # - # ==== Examples - # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007 - # - # date.to_time # => Sat Nov 10 00:00:00 0800 2007 - # date.to_time(:local) # => Sat Nov 10 00:00:00 0800 2007 - # - # date.to_time(:utc) # => Sat Nov 10 00:00:00 UTC 2007 - def to_time(form = :local) - ::Time.send("#{form}_time", year, month, day) - end + # Converts a Date instance to a Time, where the time is set to the beginning of the day. + # The timezone can be either :local or :utc (default :local). + # + # ==== Examples + # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007 + # + # date.to_time # => Sat Nov 10 00:00:00 0800 2007 + # date.to_time(:local) # => Sat Nov 10 00:00:00 0800 2007 + # + # date.to_time(:utc) # => Sat Nov 10 00:00:00 UTC 2007 + def to_time(form = :local) + ::Time.send("#{form}_time", year, month, day) + end - # Converts a Date instance to a DateTime, where the time is set to the beginning of the day - # and UTC offset is set to 0. - # - # ==== Examples - # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007 - # - # date.to_datetime # => Sat, 10 Nov 2007 00:00:00 0000 - def to_datetime - ::DateTime.civil(year, month, day, 0, 0, 0, 0) - end if RUBY_VERSION < '1.9' + # Converts a Date instance to a DateTime, where the time is set to the beginning of the day + # and UTC offset is set to 0. + # + # ==== Examples + # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007 + # + # date.to_datetime # => Sat, 10 Nov 2007 00:00:00 0000 + def to_datetime + ::DateTime.civil(year, month, day, 0, 0, 0, 0) + end if RUBY_VERSION < '1.9' - def xmlschema - to_time.xmlschema - end - end - end + def xmlschema + to_time.xmlschema end end |