diff options
Diffstat (limited to 'activesupport/lib/active_support/core_ext/time')
4 files changed, 61 insertions, 48 deletions
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 89cd7516cd..82e003fc3b 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -3,6 +3,7 @@ require 'active_support/core_ext/time/conversions' require 'active_support/time_with_zone' require 'active_support/core_ext/time/zones' require 'active_support/core_ext/date_and_time/calculations' +require 'active_support/core_ext/date/calculations' class Time include DateAndTime::Calculations @@ -15,9 +16,9 @@ class Time super || (self == Time && other.is_a?(ActiveSupport::TimeWithZone)) end - # Return the number of days in the given month. + # Returns the number of days in the given month. # If no year is specified, it will use the current year. - def days_in_month(month, year = now.year) + def days_in_month(month, year = current.year) if month == 2 && ::Date.gregorian_leap?(year) 29 else @@ -48,7 +49,11 @@ class Time alias_method :at, :at_with_coercion end - # Seconds since midnight: Time.now.seconds_since_midnight + # Returns the number of seconds since 00:00:00. + # + # Time.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0.0 + # Time.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296.0 + # Time.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399.0 def seconds_since_midnight to_i - change(:hour => 0).to_i + (usec / 1.0e+6) end @@ -64,11 +69,12 @@ class Time # Returns a new Time where one or more of the elements have been changed according # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>, - # <tt>:sec</tt>, <tt>:usec</tt>) reset cascadingly, so if only the hour is passed, - # then minute, sec, and usec is set to 0. If the hour and minute is passed, then - # sec and usec is set to 0. The +options+ parameter takes a hash with any of these - # keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, - # <tt>:sec</tt>, <tt>:usec</tt>. + # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only + # the hour is passed, then minute, sec, usec and nsec is set to 0. If the hour + # and minute is passed, then sec, usec and nsec is set to 0. The +options+ + # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, + # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt> + # <tt>:nsec</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both. # # Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0) # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0) @@ -80,13 +86,20 @@ class Time new_hour = options.fetch(:hour, hour) new_min = options.fetch(:min, options[:hour] ? 0 : min) new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec) - new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000)) + + if new_nsec = options[:nsec] + raise ArgumentError, "Can't change both :nsec and :usec at the same time: #{options.inspect}" if options[:usec] + new_usec = Rational(new_nsec, 1000) + else + new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000)) + end if utc? ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec) elsif zone ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec) else + raise ArgumentError, 'argument out of range' if new_usec >= 1000000 ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), utc_offset) end end @@ -96,6 +109,12 @@ class Time # takes a hash with any of these keys: <tt>:years</tt>, <tt>:months</tt>, # <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>, <tt>:minutes</tt>, # <tt>:seconds</tt>. + # + # Time.new(2015, 8, 1, 14, 35, 0).advance(seconds: 1) # => 2015-08-01 14:35:01 -0700 + # Time.new(2015, 8, 1, 14, 35, 0).advance(minutes: 1) # => 2015-08-01 14:36:00 -0700 + # Time.new(2015, 8, 1, 14, 35, 0).advance(hours: 1) # => 2015-08-01 15:35:00 -0700 + # Time.new(2015, 8, 1, 14, 35, 0).advance(days: 1) # => 2015-08-02 14:35:00 -0700 + # Time.new(2015, 8, 1, 14, 35, 0).advance(weeks: 1) # => 2015-08-08 14:35:00 -0700 def advance(options) unless options[:weeks].nil? options[:weeks], partial_weeks = options[:weeks].divmod(1) @@ -154,7 +173,7 @@ class Time alias :at_noon :middle_of_day alias :at_middle_of_day :middle_of_day - # Returns a new Time representing the end of the day, 23:59:59.999999 (.999999999 in ruby1.9) + # Returns a new Time representing the end of the day, 23:59:59.999999 def end_of_day change( :hour => 23, @@ -171,7 +190,7 @@ class Time end alias :at_beginning_of_hour :beginning_of_hour - # Returns a new Time representing the end of the hour, x:59:59.999999 (.999999999 in ruby1.9) + # Returns a new Time representing the end of the hour, x:59:59.999999 def end_of_hour change( :min => 59, @@ -187,7 +206,7 @@ class Time end alias :at_beginning_of_minute :beginning_of_minute - # Returns a new Time representing the end of the minute, x:xx:59.999999 (.999999999 in ruby1.9) + # Returns a new Time representing the end of the minute, x:xx:59.999999 def end_of_minute change( :sec => 59, @@ -234,8 +253,10 @@ class Time # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances # can be chronologically compared with a Time def compare_with_coercion(other) - # we're avoiding Time#to_datetime cause it's expensive - if other.is_a?(Time) + # we're avoiding Time#to_datetime and Time#to_time because they're expensive + if other.class == Time + compare_without_coercion(other) + elsif other.is_a?(Time) compare_without_coercion(other.to_time) else to_datetime <=> other diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb index dbf1f2f373..536c4bf525 100644 --- a/activesupport/lib/active_support/core_ext/time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/time/conversions.rb @@ -6,6 +6,7 @@ class Time :db => '%Y-%m-%d %H:%M:%S', :number => '%Y%m%d%H%M%S', :nsec => '%Y%m%d%H%M%S%9N', + :usec => '%Y%m%d%H%M%S%6N', :time => '%H:%M', :short => '%d %b %H:%M', :long => '%B %d, %Y %H:%M', @@ -24,7 +25,7 @@ class Time # # This method is aliased to <tt>to_s</tt>. # - # time = Time.now # => Thu Jan 18 06:10:17 CST 2007 + # time = Time.now # => 2007-01-18 06:10:17 -06:00 # # time.to_formatted_s(:time) # => "06:10" # time.to_s(:time) # => "06:10" @@ -55,7 +56,8 @@ class Time alias_method :to_default_s, :to_s alias_method :to_s, :to_formatted_s - # Returns the UTC offset as an +HH:MM formatted string. + # Returns a formatted string of the offset from UTC, or an alternative + # string if the time zone is already UTC. # # Time.local(2000).formatted_offset # => "-06:00" # Time.local(2000).formatted_offset(false) # => "-0600" diff --git a/activesupport/lib/active_support/core_ext/time/marshal.rb b/activesupport/lib/active_support/core_ext/time/marshal.rb index 497c4c3fb8..467bad1726 100644 --- a/activesupport/lib/active_support/core_ext/time/marshal.rb +++ b/activesupport/lib/active_support/core_ext/time/marshal.rb @@ -1,30 +1,3 @@ -# Ruby 1.9.2 adds utc_offset and zone to Time, but marshaling only -# preserves utc_offset. Preserve zone also, even though it may not -# work in some edge cases. -if Time.local(2010).zone != Marshal.load(Marshal.dump(Time.local(2010))).zone - class Time - class << self - alias_method :_load_without_zone, :_load - def _load(marshaled_time) - time = _load_without_zone(marshaled_time) - time.instance_eval do - if zone = defined?(@_zone) && remove_instance_variable('@_zone') - ary = to_a - ary[0] += subsec if ary[0] == sec - ary[-1] = zone - utc? ? Time.utc(*ary) : Time.local(*ary) - else - self - end - end - end - end +require 'active_support/deprecation' - alias_method :_dump_without_zone, :_dump - def _dump(*args) - obj = dup - obj.instance_variable_set('@_zone', zone) - obj.send :_dump_without_zone, *args - end - end -end +ActiveSupport::Deprecation.warn("This is deprecated and will be removed in Rails 5.1 with no replacement.") diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb index bbda04d60c..877dc84ec8 100644 --- a/activesupport/lib/active_support/core_ext/time/zones.rb +++ b/activesupport/lib/active_support/core_ext/time/zones.rb @@ -1,4 +1,5 @@ require 'active_support/time_with_zone' +require 'active_support/core_ext/time/acts_like' require 'active_support/core_ext/date_and_time/zones' class Time @@ -25,7 +26,7 @@ class Time # <tt>current_user.time_zone</tt> just needs to return a string identifying the user's preferred time zone: # # class ApplicationController < ActionController::Base - # around_filter :set_time_zone + # around_action :set_time_zone # # def set_time_zone # if logged_in? @@ -50,12 +51,22 @@ class Time end end - # Returns a TimeZone instance or nil, or raises an ArgumentError for invalid timezones. + # Returns a TimeZone instance matching the time zone provided. + # Accepts the time zone in any format supported by <tt>Time.zone=</tt>. + # Raises an +ArgumentError+ for invalid time zones. + # + # Time.find_zone! "America/New_York" # => #<ActiveSupport::TimeZone @name="America/New_York" ...> + # Time.find_zone! "EST" # => #<ActiveSupport::TimeZone @name="EST" ...> + # Time.find_zone! -5.hours # => #<ActiveSupport::TimeZone @name="Bogota" ...> + # Time.find_zone! nil # => nil + # Time.find_zone! false # => false + # Time.find_zone! "NOT-A-TIMEZONE" # => ArgumentError: Invalid Timezone: NOT-A-TIMEZONE def find_zone!(time_zone) if !time_zone || time_zone.is_a?(ActiveSupport::TimeZone) time_zone else - # lookup timezone based on identifier (unless we've been passed a TZInfo::Timezone) + # Look up the timezone based on the identifier (unless we've been + # passed a TZInfo::Timezone) unless time_zone.respond_to?(:period_for_local) time_zone = ActiveSupport::TimeZone[time_zone] || TZInfo::Timezone.get(time_zone) end @@ -71,6 +82,12 @@ class Time raise ArgumentError, "Invalid Timezone: #{time_zone}" end + # Returns a TimeZone instance matching the time zone provided. + # Accepts the time zone in any format supported by <tt>Time.zone=</tt>. + # Returns +nil+ for invalid time zones. + # + # Time.find_zone "America/New_York" # => #<ActiveSupport::TimeZone @name="America/New_York" ...> + # Time.find_zone "NOT-A-TIMEZONE" # => nil def find_zone(time_zone) find_zone!(time_zone) rescue nil end |