File: active_support/core_ext/date_time/calculations.rb

Overview
Module Structure
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: ActiveSupport#3
  module: CoreExtensions#4
  module: DateTime#5
  module: Calculations#7
has properties
module method: included / 1 #8
method: past? #29
method: future? #34
method: seconds_since_midnight #39
method: change / 1 #46
method: advance / 1 #63
method: ago / 1 #72
method: since / 1 #78
alias: in since #81
method: beginning_of_day #84
alias: midnight beginning_of_day #87
alias: at_midnight beginning_of_day #88
alias: at_beginning_of_day beginning_of_day #89
method: end_of_day #92
method: utc #102
method: utc? #108
method: utc_offset #113
method: compare_with_coercion / 1 #118
  module: ClassMethods#17
has properties
method: local_offset #19
method: current #23

Code

   1  require 'rational'
   2 
   3  module ActiveSupport #:nodoc:
   4    module CoreExtensions #:nodoc:
   5      module DateTime #:nodoc:
   6        # Enables the use of time calculations within DateTime itself
   7        module Calculations
   8          def self.included(base) #:nodoc:
   9            base.extend ClassMethods
  10 
  11            base.class_eval do
  12              alias_method :compare_without_coercion, :<=>
  13              alias_method :<=>, :compare_with_coercion
  14            end
  15          end
  16 
  17          module ClassMethods
  18            # DateTimes aren't aware of DST rules, so use a consistent non-DST offset when creating a DateTime with an offset in the local zone
  19            def local_offset
  20              ::Time.local(2007).utc_offset.to_r / 86400
  21            end
  22 
  23            def current
  24              ::Time.zone_default ? ::Time.zone.now.to_datetime : ::Time.now.to_datetime
  25            end
  26          end
  27 
  28          # Tells whether the DateTime object's datetime lies in the past
  29          def past?
  30            self < ::DateTime.current
  31          end
  32 
  33          # Tells whether the DateTime object's datetime lies in the future
  34          def future?
  35            self > ::DateTime.current
  36          end
  37 
  38          # Seconds since midnight: DateTime.now.seconds_since_midnight
  39          def seconds_since_midnight
  40            self.sec + (self.min * 60) + (self.hour * 3600)
  41          end
  42 
  43          # Returns a new DateTime where one or more of the elements have been changed according to the +options+ parameter. The time options
  44          # (hour, minute, sec) reset cascadingly, so if only the hour is passed, then minute and sec is set to 0. If the hour and
  45          # minute is passed, then sec is set to 0.
  46          def change(options)
  47            ::DateTime.civil(
  48              options[:year]  || self.year,
  49              options[:month] || self.month,
  50              options[:day]   || self.day,
  51              options[:hour]  || self.hour,
  52              options[:min]   || (options[:hour] ? 0 : self.min),
  53              options[:sec]   || ((options[:hour] || options[:min]) ? 0 : self.sec),
  54              options[:offset]  || self.offset,
  55              options[:start]  || self.start
  56            )
  57          end
  58 
  59          # Uses Date to provide precise Time calculations for years, months, and days.
  60          # The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>,
  61          # <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
  62          # <tt>:minutes</tt>, <tt>:seconds</tt>.
  63          def advance(options)
  64            d = to_date.advance(options)
  65            datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
  66            seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600
  67            seconds_to_advance == 0 ? datetime_advanced_by_date : datetime_advanced_by_date.since(seconds_to_advance)
  68          end
  69 
  70          # Returns a new DateTime representing the time a number of seconds ago
  71          # Do not use this method in combination with x.months, use months_ago instead!
  72          def ago(seconds)
  73            self.since(-seconds)
  74          end
  75 
  76          # Returns a new DateTime representing the time a number of seconds since the instance time
  77          # Do not use this method in combination with x.months, use months_since instead!
  78          def since(seconds)
  79            self + Rational(seconds.round, 86400)
  80          end
  81          alias :in :since
  82 
  83          # Returns a new DateTime representing the start of the day (0:00)
  84          def beginning_of_day
  85            change(:hour => 0)
  86          end
  87          alias :midnight :beginning_of_day
  88          alias :at_midnight :beginning_of_day
  89          alias :at_beginning_of_day :beginning_of_day
  90 
  91          # Returns a new DateTime representing the end of the day (23:59:59)
  92          def end_of_day
  93            change(:hour => 23, :min => 59, :sec => 59)
  94          end
  95 
  96          # Adjusts DateTime to UTC by adding its offset value; offset is set to 0
  97          #
  98          # Example:
  99          #
 100          #   DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24))       # => Mon, 21 Feb 2005 10:11:12 -0600
 101          #   DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc   # => Mon, 21 Feb 2005 16:11:12 +0000
 102          def utc
 103            new_offset(0)
 104          end
 105          alias_method :getutc, :utc
 106 
 107          # Returns true if offset == 0
 108          def utc?
 109            offset == 0
 110          end
 111 
 112          # Returns the offset value in seconds
 113          def utc_offset
 114            (offset * 86400).to_i
 115          end
 116 
 117          # Layers additional behavior on DateTime#<=> so that Time and ActiveSupport::TimeWithZone instances can be compared with a DateTime
 118          def compare_with_coercion(other)
 119            other = other.comparable_time if other.respond_to?(:comparable_time)
 120            other = other.to_datetime unless other.acts_like?(:date)
 121            compare_without_coercion(other)
 122          end
 123        end
 124      end
 125    end
 126  end