class Time
def ===(other)
def ===(other) super || (self == Time && other.is_a?(ActiveSupport::TimeWithZone)) end
def _dump(*args)
def _dump(*args) obj = dup obj.instance_variable_set('@_zone', zone) obj.send :_dump_without_zone, *args end
def _load(marshaled_time)
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
def acts_like_time?
def acts_like_time? true end
def advance(options)
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(hours: 1) # => 2015-08-01 15:35:00 -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(seconds: 1) # => 2015-08-01 14:35:01 -0700
:seconds.
:weeks, :days, :hours, :minutes,
takes a hash with any of these keys: :years, :months,
according to the proleptic Gregorian calendar. The +options+ parameter
Uses Date to provide precise Time calculations for years, months, and days
def advance(options) unless options[:weeks].nil? options[:weeks], partial_weeks = options[:weeks].divmod(1) options[:days] = options.fetch(:days, 0) + 7 * partial_weeks end unless options[:days].nil? options[:days], partial_days = options[:days].divmod(1) options[:hours] = options.fetch(:hours, 0) + 24 * partial_days end d = to_date.advance(options) d = d.gregorian if d.julian? time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day) seconds_to_advance = \ options.fetch(:seconds, 0) + options.fetch(:minutes, 0) * 60 + options.fetch(:hours, 0) * 3600 if seconds_to_advance.zero? time_advanced_by_date else time_advanced_by_date.since(seconds_to_advance) end end
def ago(seconds)
def ago(seconds) since(-seconds) end
def all_day
def all_day beginning_of_day..end_of_day end
def as_json(options = nil) #:nodoc:
def as_json(options = nil) #:nodoc: if ActiveSupport::JSON::Encoding.use_standard_json_time_format xmlschema(ActiveSupport::JSON::Encoding.time_precision) else %(#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}) end end
def at_with_coercion(*args)
Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime
def at_with_coercion(*args) return at_without_coercion(*args) if args.size != 1 # Time.at can be called with a time or numerical value time_or_number = args.first if time_or_number.is_a?(ActiveSupport::TimeWithZone) || time_or_number.is_a?(DateTime) at_without_coercion(time_or_number.to_f).getlocal else at_without_coercion(time_or_number) end end
def beginning_of_day
def beginning_of_day #(self - seconds_since_midnight).change(usec: 0) change(:hour => 0) end
def beginning_of_hour
def beginning_of_hour change(:min => 0) end
def beginning_of_minute
def beginning_of_minute change(:sec => 0) end
def change(options)
Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0)
Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0)
:nsec. Path either :usec or :nsec, not both.
:day, :hour, :min, :sec, :usec
parameter takes a hash with any of these keys: :year, :month,
and minute is passed, then sec, usec and nsec is set to 0. The +options+
the hour is passed, then minute, sec, usec and nsec is set to 0. If the hour
:sec, :usec, :nsec) reset cascadingly, so if only
to the +options+ parameter. The time options (:hour, :min,
Returns a new Time where one or more of the elements have been changed according
def change(options) new_year = options.fetch(:year, year) new_month = options.fetch(:month, month) new_day = options.fetch(:day, day) 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) 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
def compare_with_coercion(other)
Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
def compare_with_coercion(other) # we're avoiding Time#to_datetime cause it's expensive if other.is_a?(Time) compare_without_coercion(other.to_time) else to_datetime <=> other end end
def current
def current ::Time.zone ? ::Time.zone.now : ::Time.now end
def days_in_month(month, year = now.year)
Return the number of days in the given month.
def days_in_month(month, year = now.year) if month == 2 && ::Date.gregorian_leap?(year) 29 else COMMON_YEAR_DAYS_IN_MONTH[month] end end
def end_of_day
def end_of_day change( :hour => 23, :min => 59, :sec => 59, :usec => Rational(999999999, 1000) ) end
def end_of_hour
def end_of_hour change( :min => 59, :sec => 59, :usec => Rational(999999999, 1000) ) end
def end_of_minute
def end_of_minute change( :sec => 59, :usec => Rational(999999999, 1000) ) end
def eql_with_coercion(other)
Layers additional behavior on Time#eql? so that ActiveSupport::TimeWithZone instances
def eql_with_coercion(other) # if other is an ActiveSupport::TimeWithZone, coerce a Time instance from it so we can do eql? comparison other = other.comparable_time if other.respond_to?(:comparable_time) eql_without_coercion(other) end
def find_zone(time_zone)
def find_zone(time_zone) find_zone!(time_zone) rescue nil end
def find_zone!(time_zone)
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) unless time_zone.respond_to?(:period_for_local) time_zone = ActiveSupport::TimeZone[time_zone] || TZInfo::Timezone.get(time_zone) end # Return if a TimeZone instance, or wrap in a TimeZone instance if a TZInfo::Timezone if time_zone.is_a?(ActiveSupport::TimeZone) time_zone else ActiveSupport::TimeZone.create(time_zone.name, nil, time_zone) end end rescue TZInfo::InvalidTimezoneIdentifier raise ArgumentError, "Invalid Timezone: #{time_zone}" end
def formatted_offset(colon = true, alternate_utc_string = nil)
Time.local(2000).formatted_offset # => "-06:00"
Returns the UTC offset as an +HH:MM formatted string.
def formatted_offset(colon = true, alternate_utc_string = nil) utc? && alternate_utc_string || ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, colon) end
def middle_of_day
def middle_of_day change(:hour => 12) end
def minus_with_coercion(other)
We're layering on additional behavior so that ActiveSupport::TimeWithZone instances
Time#- can also be used to determine the number of seconds between two Time instances.
def minus_with_coercion(other) other = other.comparable_time if other.respond_to?(:comparable_time) other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other) end
def minus_with_duration(other) #:nodoc:
def minus_with_duration(other) #:nodoc: if ActiveSupport::Duration === other other.until(self) else minus_without_duration(other) end end
def plus_with_duration(other) #:nodoc:
def plus_with_duration(other) #:nodoc: if ActiveSupport::Duration === other other.since(self) else plus_without_duration(other) end end
def seconds_since_midnight
def seconds_since_midnight to_i - change(:hour => 0).to_i + (usec / 1.0e+6) end
def seconds_until_end_of_day
Time.new(2012, 8, 29, 12, 34, 56).seconds_until_end_of_day # => 41103
Time.new(2012, 8, 29, 0, 0, 0).seconds_until_end_of_day # => 86399
Returns the number of seconds until 23:59:59.
def seconds_until_end_of_day end_of_day.to_i - to_i end
def since(seconds)
def since(seconds) self + seconds rescue to_datetime.since(seconds) end
def to_formatted_s(format = :default)
Time::DATE_FORMATS[:month_and_year] = '%B %Y'
# config/initializers/time_formats.rb
or Proc instance that takes a time argument as the value.
Use the format name as the hash key and either a strftime string
You can add your own formats to the Time::DATE_FORMATS hash.
== Adding your own time formats to +to_formatted_s+
time.to_formatted_s(:iso8601) # => "2007-01-18T06:10:17-06:00"
time.to_formatted_s(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10"
time.to_formatted_s(:long) # => "January 18, 2007 06:10"
time.to_formatted_s(:short) # => "18 Jan 06:10"
time.to_formatted_s(:number) # => "20070118061017"
time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
time.to_s(:time) # => "06:10"
time.to_formatted_s(:time) # => "06:10"
time = Time.now # => Thu Jan 18 06:10:17 CST 2007
This method is aliased to to_s.
Converts to a formatted string. See DATE_FORMATS for built-in formats.
def to_formatted_s(format = :default) if formatter = DATE_FORMATS[format] formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter) else to_default_s end end
def use_zone(time_zone)
def use_zone(time_zone) new_zone = find_zone!(time_zone) begin old_zone, ::Time.zone = ::Time.zone, new_zone yield ensure ::Time.zone = old_zone end end
def zone
Returns the TimeZone for the current request, if this has been set (via Time.zone=).
def zone Thread.current[:time_zone] || zone_default end
def zone=(time_zone)
end
end
yield
else
Time.use_zone(current_user.time_zone) { yield }
if logged_in?
def set_time_zone
around_filter :set_time_zone
class ApplicationController < ActionController::Base
current_user.time_zone just needs to return a string identifying the user's preferred time zone:
Here's an example of how you might set Time.zone on a per request basis and reset it when the request is done.
* An identifier for a TZInfo::Timezone object (e.g., "America/New_York").
* A TZInfo::Timezone object.
* An identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", -5.hours).
* A Rails TimeZone object.
This method accepts any of the following:
Sets Time.zone to a TimeZone object for the current request/thread.
def zone=(time_zone) Thread.current[:time_zone] = find_zone!(time_zone) end