diff options
Diffstat (limited to 'activesupport/lib/active_support/core_ext/date_and_time/calculations.rb')
-rw-r--r-- | activesupport/lib/active_support/core_ext/date_and_time/calculations.rb | 127 |
1 files changed, 102 insertions, 25 deletions
diff --git a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb index b85e49aca5..e079af594d 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb @@ -9,15 +9,26 @@ module DateAndTime :saturday => 5, :sunday => 6 } + WEEKEND_DAYS = [ 6, 0 ] # Returns a new date/time representing yesterday. def yesterday - advance(:days => -1) + advance(days: -1) + end + + # Returns a new date/time representing the previous day. + def prev_day + advance(days: -1) end # Returns a new date/time representing tomorrow. def tomorrow - advance(:days => 1) + advance(days: 1) + end + + # Returns a new date/time representing the next day. + def next_day + advance(days: 1) end # Returns true if the date/time is today. @@ -35,6 +46,11 @@ module DateAndTime self > self.class.current end + # Returns true if the date/time falls on a Saturday or Sunday. + def on_weekend? + WEEKEND_DAYS.include?(wday) + end + # Returns a new date/time the specified number of days ago. def days_ago(days) advance(:days => -days) @@ -76,15 +92,28 @@ module DateAndTime end # Returns a new date/time at the start of the month. - # DateTime objects will have a time set to 0:00. + # + # today = Date.today # => Thu, 18 Jun 2015 + # today.beginning_of_month # => Mon, 01 Jun 2015 + # + # +DateTime+ objects will have a time set to 0:00. + # + # now = DateTime.current # => Thu, 18 Jun 2015 15:23:13 +0000 + # now.beginning_of_month # => Mon, 01 Jun 2015 00:00:00 +0000 def beginning_of_month first_hour(change(:day => 1)) end alias :at_beginning_of_month :beginning_of_month # Returns a new date/time at the start of the quarter. - # Example: 1st January, 1st July, 1st October. - # DateTime objects will have a time set to 0:00. + # + # today = Date.today # => Fri, 10 Jul 2015 + # today.beginning_of_quarter # => Wed, 01 Jul 2015 + # + # +DateTime+ objects will have a time set to 0:00. + # + # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000 + # now.beginning_of_quarter # => Wed, 01 Jul 2015 00:00:00 +0000 def beginning_of_quarter first_quarter_month = [10, 7, 4, 1].detect { |m| m <= month } beginning_of_month.change(:month => first_quarter_month) @@ -92,28 +121,62 @@ module DateAndTime alias :at_beginning_of_quarter :beginning_of_quarter # Returns a new date/time at the end of the quarter. - # Example: 31st March, 30th June, 30th September. - # DateTime objects will have a time set to 23:59:59. + # + # today = Date.today # => Fri, 10 Jul 2015 + # today.end_of_quarter # => Wed, 30 Sep 2015 + # + # +DateTime+ objects will have a time set to 23:59:59. + # + # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000 + # now.end_of_quarter # => Wed, 30 Sep 2015 23:59:59 +0000 def end_of_quarter last_quarter_month = [3, 6, 9, 12].detect { |m| m >= month } beginning_of_month.change(:month => last_quarter_month).end_of_month end alias :at_end_of_quarter :end_of_quarter - # Return a new date/time at the beginning of the year. - # Example: 1st January. - # DateTime objects will have a time set to 0:00. + # Returns a new date/time at the beginning of the year. + # + # today = Date.today # => Fri, 10 Jul 2015 + # today.beginning_of_year # => Thu, 01 Jan 2015 + # + # +DateTime+ objects will have a time set to 0:00. + # + # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000 + # now.beginning_of_year # => Thu, 01 Jan 2015 00:00:00 +0000 def beginning_of_year change(:month => 1).beginning_of_month end alias :at_beginning_of_year :beginning_of_year # Returns a new date/time representing the given day in the next week. + # + # today = Date.today # => Thu, 07 May 2015 + # today.next_week # => Mon, 11 May 2015 + # # The +given_day_in_next_week+ defaults to the beginning of the week # which is determined by +Date.beginning_of_week+ or +config.beginning_of_week+ - # when set. +DateTime+ objects have their time set to 0:00. - def next_week(given_day_in_next_week = Date.beginning_of_week) - first_hour(weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week))) + # when set. + # + # today = Date.today # => Thu, 07 May 2015 + # today.next_week(:friday) # => Fri, 15 May 2015 + # + # +DateTime+ objects have their time set to 0:00 unless +same_time+ is true. + # + # now = DateTime.current # => Thu, 07 May 2015 13:31:16 +0000 + # now.next_week # => Mon, 11 May 2015 00:00:00 +0000 + def next_week(given_day_in_next_week = Date.beginning_of_week, same_time: false) + result = first_hour(weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week))) + same_time ? copy_time_to(result) : result + end + + # Returns a new date/time representing the next weekday. + def next_weekday + if next_day.on_weekend? + next_week(:monday, same_time: true) + else + next_day + end end # Short-hand for months_since(1). @@ -134,12 +197,23 @@ module DateAndTime # Returns a new date/time representing the given day in the previous week. # Week is assumed to start on +start_day+, default is # +Date.beginning_of_week+ or +config.beginning_of_week+ when set. - # DateTime objects have their time set to 0:00. - def prev_week(start_day = Date.beginning_of_week) - first_hour(weeks_ago(1).beginning_of_week.days_since(days_span(start_day))) + # DateTime objects have their time set to 0:00 unless +same_time+ is true. + def prev_week(start_day = Date.beginning_of_week, same_time: false) + result = first_hour(weeks_ago(1).beginning_of_week.days_since(days_span(start_day))) + same_time ? copy_time_to(result) : result end alias_method :last_week, :prev_week + # Returns a new date/time representing the previous weekday. + def prev_weekday + if prev_day.on_weekend? + copy_time_to(beginning_of_week(:friday)) + else + prev_day + end + end + alias_method :last_weekday, :prev_weekday + # Short-hand for months_ago(1). def prev_month months_ago(1) @@ -235,17 +309,20 @@ module DateAndTime end private + def first_hour(date_or_time) + date_or_time.acts_like?(:time) ? date_or_time.beginning_of_day : date_or_time + end - def first_hour(date_or_time) - date_or_time.acts_like?(:time) ? date_or_time.beginning_of_day : date_or_time - end + def last_hour(date_or_time) + date_or_time.acts_like?(:time) ? date_or_time.end_of_day : date_or_time + end - def last_hour(date_or_time) - date_or_time.acts_like?(:time) ? date_or_time.end_of_day : date_or_time - end + def days_span(day) + (DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7 + end - def days_span(day) - (DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7 - end + def copy_time_to(other) + other.change(hour: hour, min: min, sec: sec, usec: try(:usec)) + end end end |