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('@marshal_with_utc_coercion', utc?) obj.send :_dump_without_utc_flag, *args 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_utc_flag(marshaled_time) time.instance_eval do if defined?(@marshal_with_utc_coercion) val = remove_instance_variable("@marshal_with_utc_coercion") end val ? utc : self end 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)
:months, :weeks, :days, :hours,
The +options+ parameter takes a hash with any of these keys: :years,
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[:days] || 0) + 7 * partial_weeks end unless options[:days].nil? options[:days], partial_days = options[:days].divmod(1) options[:hours] = (options[:hours] || 0) + 24 * partial_days end d = to_date.advance(options) time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day) seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600 seconds_to_advance == 0 ? time_advanced_by_date : time_advanced_by_date.since(seconds_to_advance) end
def ago(seconds)
def ago(seconds) since(-seconds) end
def all_day
def all_day beginning_of_day..end_of_day end
def all_month
def all_month beginning_of_month..end_of_month end
def all_quarter
def all_quarter beginning_of_quarter..end_of_quarter end
def all_week(start_day = :monday)
def all_week(start_day = :monday) beginning_of_week(start_day)..end_of_week(start_day) end
def all_year
def all_year beginning_of_year..end_of_year end
def as_json(options = nil) #:nodoc:
def as_json(options = nil) #:nodoc: if ActiveSupport.use_standard_json_time_format xmlschema 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_month
def beginning_of_month #self - ((self.mday-1).days + self.seconds_since_midnight) change(:day => 1, :hour => 0) end
def beginning_of_quarter
def beginning_of_quarter beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= month }) end
def beginning_of_week(start_day = :monday)
def beginning_of_week(start_day = :monday) days_to_start = days_to_week_start(start_day) (self - days_to_start.days).midnight end
def beginning_of_year
def beginning_of_year change(:month => 1, :day => 1, :hour => 0) end
def change(options)
(hour, min, sec, usec) reset cascadingly, so if only the hour is passed, then minute, sec, and usec is set to 0. If the hour and
Returns a new Time where one or more of the elements have been changed according to the +options+ parameter. The time options
def change(options) ::Time.send( utc? ? :utc_time : :local_time, options[:year] || year, options[:month] || month, options[:day] || day, options[:hour] || hour, options[:min] || (options[:hour] ? 0 : min), options[:sec] || ((options[:hour] || options[:min]) ? 0 : sec), options[:usec] || ((options[:hour] || options[:min] || options[:sec]) ? 0 : usec) ) 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 other.is_a?(Time) ? compare_without_coercion(other.to_time) : to_datetime <=> other 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) return 29 if month == 2 && ::Date.gregorian_leap?(year) COMMON_YEAR_DAYS_IN_MONTH[month] end
def days_to_week_start(start_day = :monday)
def days_to_week_start(start_day = :monday) start_day_number = DAYS_INTO_WEEK[start_day] current_day_number = wday != 0 ? wday - 1 : 6 days_span = current_day_number - start_day_number days_span >= 0 ? days_span : 7 + days_span 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_month
def end_of_month #self - ((self.mday-1).days + self.seconds_since_midnight) last_day = ::Time.days_in_month(month, year) change(:day => last_day, :hour => 23, :min => 59, :sec => 59, :usec => Rational(999999999, 1000)) end
def end_of_quarter
def end_of_quarter beginning_of_month.change(:month => [3, 6, 9, 12].detect { |m| m >= month }).end_of_month end
def end_of_week(start_day = :monday)
def end_of_week(start_day = :monday) days_to_end = 6 - days_to_week_start(start_day) (self + days_to_end.days).end_of_day end
def end_of_year
def end_of_year change(:month => 12, :day => 31, :hour => 23, :min => 59, :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) return time_zone if time_zone.nil? || time_zone.is_a?(ActiveSupport::TimeZone) # 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 time_zone.is_a?(ActiveSupport::TimeZone) ? time_zone : ActiveSupport::TimeZone.create(time_zone.name, nil, time_zone) 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 future?
def future? self > ::Time.current end
def in_time_zone(zone = ::Time.zone)
and the conversion will be based on that zone instead of Time.zone.
You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
instead of the operating system's time zone.
This method is similar to Time#localtime, except that it uses Time.zone as the local zone
Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00
Time.zone = 'Hawaii' # => 'Hawaii'
Returns the simultaneous time in Time.zone.
def in_time_zone(zone = ::Time.zone) return self unless zone ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.find_zone!(zone)) end
def local_time(*args)
def local_time(*args) time_with_datetime_fallback(:local, *args) 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 monday
Returns a new +Date+/+DateTime+ representing the start of this week. Week is
def monday beginning_of_week end
def months_ago(months)
def months_ago(months) advance(:months => -months) end
def months_since(months)
def months_since(months) advance(:months => months) end
def next_month
def next_month months_since(1) end
def next_week(day = :monday)
def next_week(day = :monday) since(1.week).beginning_of_week.since(DAYS_INTO_WEEK[day].day).change(:hour => 0) end
def next_year
def next_year years_since(1) end
def past?
def past? self < ::Time.current 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 prev_month
def prev_month months_ago(1) end
def prev_week(day = :monday)
def prev_week(day = :monday) ago(1.week).beginning_of_week.since(DAYS_INTO_WEEK[day].day).change(:hour => 0) end
def prev_year
def prev_year years_ago(1) end
def seconds_since_midnight
def seconds_since_midnight to_i - change(:hour => 0).to_i + (usec / 1.0e+6) end
def since(seconds)
def since(seconds) self + seconds rescue to_datetime.since(seconds) end
def sunday
Returns a new +Date+/+DateTime+ representing the end of this week. Week is
def sunday end_of_week end
def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
(i.e., if year is within either 1970..2038 or 1902..2038, depending on system architecture);
Returns a new Time if requested year can be accommodated by Ruby's Time class
def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0) time = ::Time.send(utc_or_local, year, month, day, hour, min, sec, usec) # This check is needed because Time.utc(y) returns a time object in the 2000s for 0 <= y <= 138. time.year == year ? time : ::DateTime.civil_from_format(utc_or_local, year, month, day, hour, min, sec) rescue ::DateTime.civil_from_format(utc_or_local, year, month, day, hour, min, sec) end
def to_date
your_time = Time.parse("1/13/2009 1:13:03 P.M.") # => Tue Jan 13 13:13:03 -0500 2009
my_time.to_date # => Mon, 12 Nov 2007
my_time = Time.now # => Mon Nov 12 22:59:51 -0500 2007
Converts a Time object to a Date, dropping hour, minute, and second precision.
def to_date ::Date.new(year, month, day) end unless method_defined?(:to_date)
def to_datetime
your_time = Time.parse("1/13/2009 1:13:03 P.M.") # => Tue Jan 13 13:13:03 -0500 2009
my_time.to_datetime # => Mon, 12 Nov 2007 23:04:21 -0500
my_time = Time.now # => Mon Nov 12 23:04:21 -0500 2007
Converts a Time instance to a Ruby DateTime instance, preserving UTC offset.
def to_datetime ::DateTime.civil(year, month, day, hour, min, sec, Rational(utc_offset, 86400)) end unless method_defined?(:to_datetime)
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(: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 builtin 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 to_time
A method to keep Time, Date and DateTime instances interchangeable on conversions.
def to_time self end unless method_defined?(:to_time)
def today?
def today? to_date == ::Date.current end
def tomorrow
def tomorrow advance(:days => 1) 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 utc_time(*args)
def utc_time(*args) time_with_datetime_fallback(:utc, *args) end
def weeks_ago(weeks)
def weeks_ago(weeks) advance(:weeks => -weeks) end
def years_ago(years)
def years_ago(years) advance(:years => -years) end
def years_since(years)
def years_since(years) advance(:years => years) end
def yesterday
def yesterday advance(:days => -1) 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
Time.zone = old_time_zone
ensure
yield
Time.zone = current_user.time_zone if logged_in?
old_time_zone = Time.zone
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