calculations.rb 4.7 KB
Newer Older
B
brainopia 已提交
1 2
require 'active_support/deprecation'

3 4
class DateTime
  class << self
B
brainopia 已提交
5
    # *DEPRECATED*: Use +DateTime.civil_from_format+ directly.
6
    def local_offset
7
      ActiveSupport::Deprecation.warn 'DateTime.local_offset is deprecated. Use DateTime.civil_from_format directly.'
A
Alexey Gaziev 已提交
8

B
brainopia 已提交
9
      ::Time.local(2012).utc_offset.to_r / 86400
10
    end
11

12 13 14
    # Returns <tt>Time.zone.now.to_datetime</tt> when <tt>Time.zone</tt> or
    # <tt>config.time_zone</tt> are set, otherwise returns
    # <tt>Time.now.to_datetime</tt>.
15
    def current
16
      ::Time.zone ? ::Time.zone.now.to_datetime : ::Time.now.to_datetime
17 18
    end
  end
19

20
  # Tells whether the DateTime object's datetime lies in the past.
21 22 23
  def past?
    self < ::DateTime.current
  end
24

25
  # Tells whether the DateTime object's datetime lies in the future.
26 27 28
  def future?
    self > ::DateTime.current
  end
29

30
  # Seconds since midnight: DateTime.now.seconds_since_midnight.
31 32 33
  def seconds_since_midnight
    sec + (min * 60) + (hour * 3600)
  end
34

35 36 37 38 39 40 41
  # Returns a new DateTime where one or more of the elements have been changed
  # according to the +options+ parameter. The time options (<tt>:hour</tt>,
  # <tt>:minute</tt>, <tt>:sec</tt>) reset cascadingly, so if only the hour is
  # passed, then minute and sec is set to 0. If the hour and minute is passed,
  # then sec 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>:offset</tt>, <tt>:start</tt>.
42
  #
43 44 45
  #   DateTime.new(2012, 8, 29, 22, 35, 0).change(day: 1)              # => DateTime.new(2012, 8, 1, 22, 35, 0)
  #   DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1)  # => DateTime.new(1981, 8, 1, 22, 35, 0)
  #   DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => DateTime.new(1981, 8, 29, 0, 0, 0)
46 47
  def change(options)
    ::DateTime.civil(
A
Alexey Gaziev 已提交
48 49 50 51 52 53 54 55
      options.fetch(:year, year),
      options.fetch(:month, month),
      options.fetch(:day, day),
      options.fetch(:hour, hour),
      options.fetch(:min, options[:hour] ? 0 : min),
      options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec),
      options.fetch(:offset, offset),
      options.fetch(:start, start)
56 57
    )
  end
58

59 60 61 62 63 64 65
  # Uses Date to provide precise Time calculations for years, months, and days.
  # The +options+ parameter 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>.
  def advance(options)
    d = to_date.advance(options)
    datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
A
Alexey Gaziev 已提交
66 67 68 69 70 71 72 73 74 75
    seconds_to_advance = \
      options.fetch(:seconds, 0) +
      options.fetch(:minutes, 0) * 60 +
      options.fetch(:hours, 0) * 3600

    if seconds_to_advance.zero?
      datetime_advanced_by_date
    else
      datetime_advanced_by_date.since seconds_to_advance
    end
76
  end
77

78
  # Returns a new DateTime representing the time a number of seconds ago.
79 80 81 82
  # Do not use this method in combination with x.months, use months_ago instead!
  def ago(seconds)
    since(-seconds)
  end
83

84 85 86
  # Returns a new DateTime representing the time a number of seconds since the
  # instance time. Do not use this method in combination with x.months, use
  # months_since instead!
87 88 89 90
  def since(seconds)
    self + Rational(seconds.round, 86400)
  end
  alias :in :since
91

92
  # Returns a new DateTime representing the start of the day (0:00).
93 94 95 96 97 98
  def beginning_of_day
    change(:hour => 0)
  end
  alias :midnight :beginning_of_day
  alias :at_midnight :beginning_of_day
  alias :at_beginning_of_day :beginning_of_day
99

100
  # Returns a new DateTime representing the end of the day (23:59:59).
101 102 103
  def end_of_day
    change(:hour => 23, :min => 59, :sec => 59)
  end
104

105
  # Returns a new DateTime representing the start of the hour (hh:00:00).
106 107 108 109 110
  def beginning_of_hour
    change(:min => 0)
  end
  alias :at_beginning_of_hour :beginning_of_hour

111
  # Returns a new DateTime representing the end of the hour (hh:59:59).
112 113 114 115
  def end_of_hour
    change(:min => 59, :sec => 59)
  end

116
  # Adjusts DateTime to UTC by adding its offset value; offset is set to 0.
117
  #
118 119
  #   DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24))     # => Mon, 21 Feb 2005 10:11:12 -0600
  #   DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 +0000
120 121 122 123
  def utc
    new_offset(0)
  end
  alias_method :getutc, :utc
124

125
  # Returns +true+ if <tt>offset == 0</tt>.
126 127 128
  def utc?
    offset == 0
  end
129

130
  # Returns the offset value in seconds.
131 132 133
  def utc_offset
    (offset * 86400).to_i
  end
134

135 136
  # Layers additional behavior on DateTime#<=> so that Time and
  # ActiveSupport::TimeWithZone instances can be compared with a DateTime.
137 138
  def <=>(other)
    super other.to_datetime
139
  end
A
Alexey Gaziev 已提交
140

141
end