класс Time
Константы
- COMMON_YEAR_DAYS_IN_MONTH
- DATE_FORMATS
Атрибуты
Открытые методы класса
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 18 def ===(other) super || (self == Time && other.is_a?(ActiveSupport::TimeWithZone)) end
Переопределение метода равенства по значениям, чтобы он возвращал true для экземпляров ActiveSupport::TimeWithZone
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 45
def at_with_coercion(time_or_number, *args)
if args.empty?
if time_or_number.is_a?(ActiveSupport::TimeWithZone)
at_without_coercion(time_or_number.to_r).getlocal
elsif time_or_number.is_a?(DateTime)
at_without_coercion(time_or_number.to_f).getlocal
else
at_without_coercion(time_or_number)
end
else
at_without_coercion(time_or_number, *args)
end
end Добавляет дополнительное поведение к методу Time.at, чтобы можно было использовать экземпляры ActiveSupport::TimeWithZone и DateTime при вызове с одним аргументом
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 39 def current ::Time.zone ? ::Time.zone.now : ::Time.now end
Возвращает Time.zone.now, если Time.zone или config.time_zone заданы, иначе возвращает Time.now.
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 24
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 Возвращает количество дней в указанном месяце. Если год не указан, используется текущий год.
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 34 def days_in_year(year = current.year) days_in_month(2, year) + 337 end
Возвращает количество дней в указанном году. Если год не указан, используется текущий год.
# File activesupport/lib/active_support/core_ext/time/zones.rb, line 93 def find_zone(time_zone) find_zone!(time_zone) rescue nil end
Возвращает экземпляр TimeZone, соответствующий заданной временной зоне. Принимает временную зону в любом формате, поддерживаемом Time.zone=. Возвращает nil для неверных временных зон.
Time.find_zone "America/New_York" # => #<ActiveSupport::TimeZone @name="America/New_York" ...> Time.find_zone "NOT-A-TIMEZONE" # => nil
# File activesupport/lib/active_support/core_ext/time/zones.rb, line 81
def find_zone!(time_zone)
return time_zone unless time_zone
ActiveSupport::TimeZone[time_zone] || raise(ArgumentError, "Invalid Timezone: #{time_zone}")
end Возвращает экземпляр TimeZone, соответствующий заданной временной зоне. Принимает временную зону в любом формате, поддерживаемом Time.zone=. Выбрасывает ArgumentError для неверных временных зон.
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
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 69
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 Создает экземпляр Time из строки RFC 3339.
Time.rfc3339('1999-12-31T14:00:00-10:00') # => 2000-01-01 00:00:00 -1000
Если отсутствуют компоненты времени или смещения, будет вызвано исключение ArgumentError.
Time.rfc3339('1999-12-31') # => ArgumentError: invalid date
# File activesupport/lib/active_support/core_ext/time/zones.rb, line 61
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 Позволяет локально переопределить Time.zone внутри переданного блока; сбрасывает Time.zone к предыдущему значению по завершении.
class ApplicationController < ActionController::Base
around_action :set_time_zone
private
def set_time_zone
Time.use_zone(current_user.timezone) { yield }
end
end
ПРИМЕЧАНИЕ: Это не повлияет на объекты ActiveSupport::TimeWithZone, которые уже были созданы, например, атрибуты отметки времени модели, которые были прочитаны до блока, останутся в по умолчанию временной зоне приложения.
# File activesupport/lib/active_support/core_ext/time/zones.rb, line 14 def zone ::ActiveSupport::IsolatedExecutionState[:time_zone] || zone_default end
Возвращает TimeZone для текущего запроса, если он был установлен (через Time.zone=). Если Time.zone не был установлен для текущего запроса, возвращается TimeZone, указанный в config.time_zone.
# File activesupport/lib/active_support/core_ext/time/zones.rb, line 41 def zone=(time_zone) ::ActiveSupport::IsolatedExecutionState[:time_zone] = find_zone!(time_zone) end
Устанавливает Time.zone на объект TimeZone для текущего запроса/потока.
Этот метод принимает любое из следующего:
-
Объект Rails TimeZone.
-
Идентификатор объекта Rails TimeZone (например, «Eastern
Time(US & Canada)»,-5.hours). -
Объект
TZInfo::Timezone. -
Идентификатор объекта
TZInfo::Timezone(например, “America/New_York”).
Вот пример того, как можно установить Time.zone на основе каждого запроса и сбросить его по завершении запроса. current_user.time_zone просто должен вернуть строку, определяющую предпочтительную временную зону пользователя:
class ApplicationController < ActionController::Base
around_action :set_time_zone
def set_time_zone
if logged_in?
Time.use_zone(current_user.time_zone) { yield }
else
yield
end
end
end
Методы экземпляров Public
# File activesupport/lib/active_support/core_ext/time/acts_like.rb, line 7 def acts_like_time? true end
Имитирует класс Time. См. Object#acts_like?.
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 187
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 Использует Date для точных вычислений Time по годам, месяцам и дням по пролептическому григорианскому календарю. Параметр options принимает хэш с любыми из этих ключей: :years, :months, :weeks, :days, :hours, :minutes, :seconds.
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
Так же, как и в Date#advance, инкременты применяются в порядке от наибольших к наименьшим единицам времени. Этот порядок может влиять на результат около конца месяца.
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 226 def beginning_of_day change(hour: 0) end
Возвращает новый Time, представляющий начало дня (0:00)
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 255 def beginning_of_hour change(min: 0) end
Возвращает новый Time, представляющий начало часа (x:00)
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 271 def beginning_of_minute change(sec: 0) end
Возвращает новый Time, представляющий начало минуты (x:xx:00)
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 123
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.respond_to?(:utc_to_local)
new_time = ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
# When there are two occurrences of a nominal time due to DST ending,
# `Time.new` chooses the first chronological occurrence (the one with a
# larger UTC offset). However, for `change`, we want to choose the
# occurrence that matches this time's UTC offset.
#
# If the new time's UTC offset is larger than this time's UTC offset, the
# new time might be a first chronological occurrence. So we add the offset
# difference to fast-forward the new time, and check if the result has the
# desired UTC offset (i.e. is the second chronological occurrence).
offset_difference = new_time.utc_offset - utc_offset
if offset_difference > 0 && (new_time_2 = new_time + offset_difference).utc_offset == utc_offset
new_time_2
else
new_time
end
elsif zone
::Time.local(new_sec, new_min, new_hour, new_day, new_month, new_year, nil, nil, isdst, nil)
else
::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
end
end Возвращает новый Time, где один или несколько элементов были изменены согласно параметру options. Опции времени (:hour, :min, :sec, :usec, :nsec) сбрасываются каскадно. Если передан только час, то минута, секунда, микросекунда и наносекунда устанавливаются в 0. Если передан час и минута, то секунда, микросекунда и наносекунда устанавливаются в 0. Параметр options принимает хэш с любыми из этих ключей: :year, :month, :day, :hour, :min, :sec, :usec, :nsec, :offset. Передайте либо :usec, либо :nsec, а не оба.
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) Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => Time.new(1981, 8, 29, 0, 0, 0)
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 317
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)
# also avoid ActiveSupport::TimeWithZone#to_time before Rails 8.0
if other.respond_to?(:comparable_time)
compare_without_coercion(other.comparable_time)
else
compare_without_coercion(other.to_time)
end
else
to_datetime <=> other
end
end Добавляет дополнительное поведение к Time#<=>, чтобы экземпляры DateTime и ActiveSupport::TimeWithZone можно было сравнивать по времени с Time
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 244
def end_of_day
change(
hour: 23,
min: 59,
sec: 59,
usec: Rational(999999999, 1000)
)
end Возвращает новый Time, представляющий конец дня, 23:59:59.999999
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 261
def end_of_hour
change(
min: 59,
sec: 59,
usec: Rational(999999999, 1000)
)
end Возвращает новый Time, представляющий конец часа, x:59:59.999999
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 277
def end_of_minute
change(
sec: 59,
usec: Rational(999999999, 1000)
)
end Возвращает новый Time, представляющий конец минуты, x:xx:59.999999
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 337 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
Добавляет дополнительное поведение к Time#eql?, чтобы экземпляры ActiveSupport::TimeWithZone могли быть eql? эквивалентному Time
# File activesupport/lib/active_support/core_ext/time/conversions.rb, line 67 def formatted_offset(colon = true, alternate_utc_string = nil) utc? && alternate_utc_string || ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, colon) end
Возвращает отформатированную строку смещения от UTC или альтернативную строку, если часовой пояс уже UTC.
Time.local(2000).formatted_offset # => "-06:00" Time.local(2000).formatted_offset(false) # => "-0600"
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 234 def middle_of_day change(hour: 12) end
Возвращает новый Time, представляющий полдень (12:00)
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 308 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
- также может использоваться для определения количества секунд между двумя Time. Мы добавляем дополнительное поведение, чтобы экземпляры ActiveSupport::TimeWithZone были приведены к значениям, которые - распознает.
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 351 def next_day(days = 1) advance(days: days) end
Возвращает новое время, на заданное количество дней в будущем.
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 361 def next_month(months = 1) advance(months: months) end
Возвращает новое время, на заданное количество месяцев в будущем.
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 371 def next_year(years = 1) advance(years: years) end
Возвращает новое время, на заданное количество лет в будущем.
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 346 def prev_day(days = 1) advance(days: -days) end
Возвращает новое время, на заданное количество дней назад.
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 356 def prev_month(months = 1) advance(months: -months) end
Возвращает новое время, на заданное количество месяцев назад.
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 366 def prev_year(years = 1) advance(years: -years) end
Возвращает новое время, на заданное количество лет назад.
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 107 def sec_fraction subsec end
Возвращает дробную часть секунды как Rational
Time.new(2012, 8, 29, 0, 0, 0.5).sec_fraction # => (1/2)
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 91 def seconds_since_midnight to_i - change(hour: 0).to_i + (usec / 1.0e+6) end
Возвращает количество секунд с 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
# File activesupport/lib/active_support/core_ext/time/calculations.rb, line 100 def seconds_until_end_of_day end_of_day.to_i - to_i end
Возвращает количество секунд до 23:59:59.
Time.new(2012, 8, 29, 0, 0, 0).seconds_until_end_of_day # => 86399 Time.new(2012, 8, 29, 12, 34, 56).seconds_until_end_of_day # => 41103 Time.new(2012, 8, 29, 23, 59, 59).seconds_until_end_of_day # => 0
# File activesupport/lib/active_support/core_ext/time/conversions.rb, line 53
def to_fs(format = :default)
if formatter = DATE_FORMATS[format]
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
else
to_s
end
end Преобразует в отформатированную строку. См. DATE_FORMATS для встроенных форматов.
Этот метод является псевдонимом для to_formatted_s.
time = Time.now # => 2007-01-18 06:10:17 -06:00 time.to_fs(:time) # => "06:10" time.to_formatted_s(:time) # => "06:10" time.to_fs(:db) # => "2007-01-18 06:10:17" time.to_fs(:number) # => "20070118061017" time.to_fs(:short) # => "18 Jan 06:10" time.to_fs(:long) # => "January 18, 2007 06:10" time.to_fs(:long_ordinal) # => "January 18th, 2007 06:10" time.to_fs(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600" time.to_fs(:iso8601) # => "2007-01-18T06:10:17-06:00"
Добавление собственных форматов времени в to_fs
Вы можете добавить собственные форматы в хэш Time::DATE_FORMATS. Используйте имя формата в качестве ключа хэша и либо строку strftime, либо экземпляр Proc, принимающий аргумент времени, в качестве значения.
# config/initializers/time_formats.rb
Time::DATE_FORMATS[:month_and_year] = '%B %Y'
Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
# File activesupport/lib/active_support/core_ext/time/compatibility.rb, line 13 def to_time preserve_timezone ? self : getlocal end
Возвращает self или время в часовом поясе локальной системы в зависимости от настроек ActiveSupport.to_time_preserves_timezone.
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.