class Time

:nodoc:

def ===(other)

Overriding case equality method so that it returns true for ActiveSupport::TimeWithZone instances
def ===(other)
  super || (self == Time && other.is_a?(ActiveSupport::TimeWithZone))
end

def acts_like_time?

Duck-types as a Time-like class. See Object#acts_like?.
def acts_like_time?
  true
end

def advance(options)

Time.new(2015, 8, 1, 14, 35, 0).advance(weeks: 1) # => 2015-08-08 14: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(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.gregorian.advance(options)
  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)

Returns a new Time representing the time a number of seconds ago, this is basically a wrapper around the Numeric extension
def ago(seconds)
  since(-seconds)
end

def as_json(options = nil) #:nodoc:

: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)

instances can be used when called with a single argument
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

Returns a new Time representing the start of the day (0:00)
def beginning_of_day
  change(hour: 0)
end

def beginning_of_hour

Returns a new Time representing the start of the hour (x:00)
def beginning_of_hour
  change(min: 0)
end

def beginning_of_minute

Returns a new Time representing the start of the minute (x:xx:00)
def beginning_of_minute
  change(sec: 0)
end

def blank?

Returns:
  • (false) -
def blank?
  false
end

def change(options)

Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => Time.new(1981, 8, 29, 0, 0, 0)
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)

:offset. Pass either :usec or :nsec, not both.
:hour, :min, :sec, :usec, :nsec,
takes a hash with any of these keys: :year, :month, :day,
and minute is passed, then sec, usec and nsec is set to 0. The +options+ parameter
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)
  new_offset = options.fetch(:offset, nil)
  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
  raise ArgumentError, "argument out of range" if new_usec >= 1000000
  new_sec += Rational(new_usec, 1000000)
  if new_offset
    ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
  elsif utc?
    ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
  elsif zone
    ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec)
  else
    ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
  end
end

def compare_with_coercion(other)

can be chronologically compared with a Time
Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
def compare_with_coercion(other)
  # 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
  end
end

def current

Returns Time.zone.now when Time.zone or config.time_zone are set, otherwise just returns Time.now.
def current
  ::Time.zone ? ::Time.zone.now : ::Time.now
end

def days_in_month(month, year = current.year)

If no year is specified, it will use the current year.
Returns the number of days in the given month.
def days_in_month(month, year = current.year)
  if month == 2 && ::Date.gregorian_leap?(year)
    29
  else
    COMMON_YEAR_DAYS_IN_MONTH[month]
  end
end

def days_in_year(year = current.year)

If no year is specified, it will use the current year.
Returns the number of days in the given year.
def days_in_year(year = current.year)
  days_in_month(2, year) + 337
end

def end_of_day

Returns a new Time representing the end of the day, 23:59:59.999999
def end_of_day
  change(
    hour: 23,
    min: 59,
    sec: 59,
    usec: Rational(999999999, 1000)
  )
end

def end_of_hour

Returns a new Time representing the end of the hour, x:59:59.999999
def end_of_hour
  change(
    min: 59,
    sec: 59,
    usec: Rational(999999999, 1000)
  )
end

def end_of_minute

Returns a new Time representing the end of the minute, x:xx:59.999999
def end_of_minute
  change(
    sec: 59,
    usec: Rational(999999999, 1000)
  )
end

def eql_with_coercion(other)

can be eql? to an equivalent Time
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)

Time.find_zone "NOT-A-TIMEZONE" # => nil
Time.find_zone "America/New_York" # => #

Returns +nil+ for invalid time zones.
Accepts the time zone in any format supported by Time.zone=.
Returns a TimeZone instance matching the time zone provided.
def find_zone(time_zone)
  find_zone!(time_zone) rescue nil
end

def find_zone!(time_zone)

Time.find_zone! "NOT-A-TIMEZONE" # => ArgumentError: Invalid Timezone: NOT-A-TIMEZONE
Time.find_zone! false # => false
Time.find_zone! nil # => nil
Time.find_zone! -5.hours # => #
Time.find_zone! "EST" # => #
Time.find_zone! "America/New_York" # => #

Raises an +ArgumentError+ for invalid time zones.
Accepts the time zone in any format supported by Time.zone=.
Returns a TimeZone instance matching the time zone provided.
def find_zone!(time_zone)
  if !time_zone || time_zone.is_a?(ActiveSupport::TimeZone)
    time_zone
  else
    # 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
    # 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(false) # => "-0600"
Time.local(2000).formatted_offset # => "-06:00"

string if the time zone is already UTC.
Returns a formatted string of the offset from UTC, or an alternative
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

Returns a new Time representing the middle of the day (12:00)
def middle_of_day
  change(hour: 12)
end

def minus_with_coercion(other)

are coerced into values that Time#- will recognize
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:

:nodoc:
def minus_with_duration(other) #:nodoc:
  if ActiveSupport::Duration === other
    other.until(self)
  else
    minus_without_duration(other)
  end
end

def next_day(days = 1)

Returns a new time the specified number of days in the future.
def next_day(days = 1)
  advance(days: days)
end

def next_month(months = 1)

Returns a new time the specified number of months in the future.
def next_month(months = 1)
  advance(months: months)
end

def next_year(years = 1)

Returns a new time the specified number of years in the future.
def next_year(years = 1)
  advance(years: years)
end

def plus_with_duration(other) #:nodoc:

:nodoc:
def plus_with_duration(other) #:nodoc:
  if ActiveSupport::Duration === other
    other.since(self)
  else
    plus_without_duration(other)
  end
end

def prev_day(days = 1)

Returns a new time the specified number of days ago.
def prev_day(days = 1)
  advance(days: -days)
end

def prev_month(months = 1)

Returns a new time the specified number of months ago.
def prev_month(months = 1)
  advance(months: -months)
end

def prev_year(years = 1)

Returns a new time the specified number of years ago.
def prev_year(years = 1)
  advance(years: -years)
end

def rfc3339(str)

Time.rfc3339('1999-12-31') # => ArgumentError: invalid date

If the time or offset components are missing then an +ArgumentError+ will be raised.

Time.rfc3339('1999-12-31T14:00:00-10:00') # => 2000-01-01 00:00:00 -1000

Creates a +Time+ instance from an RFC 3339 string.
def rfc3339(str)
  parts = Date._rfc3339(str)
  raise ArgumentError, "invalid date" if parts.empty?
  Time.new(
    parts.fetch(:year),
    parts.fetch(:mon),
    parts.fetch(:mday),
    parts.fetch(:hour),
    parts.fetch(:min),
    parts.fetch(:sec) + parts.fetch(:sec_fraction, 0),
    parts.fetch(:offset)
  )
end

def sec_fraction

Time.new(2012, 8, 29, 0, 0, 0.5).sec_fraction # => (1/2)

Returns the fraction of a second as a +Rational+
def sec_fraction
  subsec
end

def seconds_since_midnight

Time.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399.0
Time.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296.0
Time.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0.0

Returns the number of seconds since 00:00:00.
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, 23, 59, 59).seconds_until_end_of_day # => 0
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)

Returns a new Time representing the time a number of seconds since the instance time
def since(seconds)
  self + seconds
rescue
  to_datetime.since(seconds)
end

def to_formatted_s(format = :default)

Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
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 # => 2007-01-18 06:10:17 -06:00

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 to_time

on the setting of +ActiveSupport.to_time_preserves_timezone+.
Either return +self+ or the time in the local system timezone depending
def to_time
  preserve_timezone ? self : getlocal
end

def use_zone(time_zone)

the application's default timezone.
attributes that have been read before the block will remain in
objects that have already been created, e.g. any model timestamp
NOTE: This won't affect any ActiveSupport::TimeWithZone

end
end
Time.use_zone(current_user.timezone) { yield }
def set_time_zone

private

around_action :set_time_zone
class ApplicationController < ActionController::Base

resets Time.zone to existing value when done.
Allows override of Time.zone locally inside supplied block;
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

If Time.zone has not been set for the current request, returns the TimeZone specified in config.time_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
end
yield
else
Time.use_zone(current_user.time_zone) { yield }
if logged_in?
def set_time_zone

around_action :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