Skip to content

Commit

Permalink
Add Date and Time #yesterday? and #tomorrow? (#37625)
Browse files Browse the repository at this point in the history
Add Date and Time `#yesterday?` and `#tomorrow?` alongside `#today?`.

Aliased to `#prev_day?` and `#next_day?` to match the existing `#prev/next_day` methods.
  • Loading branch information
jatindhankhar committed Mar 20, 2020
1 parent e91b3b2 commit 5df9b45
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 3 deletions.
6 changes: 6 additions & 0 deletions activesupport/CHANGELOG.md
@@ -1,3 +1,9 @@
* Add Date and Time `#yesterday?` and `#tomorrow?` alongside `#today?`.

Aliased to `#prev_day?` and `#next_day?` to match the existing `#prev/next_day` methods.

*Jatin Dhankhar*

* Add `Enumerable#pick` to complement `ActiveRecord::Relation#pick`.

*Eugene Kenny*
Expand Down
Expand Up @@ -31,6 +31,18 @@ def today?
to_date == ::Date.current
end

# Returns true if the date/time is tomorrow.
def tomorrow?
to_date == ::Date.current.tomorrow
end
alias :next_day? :tomorrow?

# Returns true if the date/time is yesterday.
def yesterday?
to_date == ::Date.current.yesterday
end
alias :prev_day? :yesterday?

# Returns true if the date/time is in the past.
def past?
self < self.class.current
Expand Down
14 changes: 14 additions & 0 deletions activesupport/lib/active_support/time_with_zone.rb
Expand Up @@ -245,6 +245,20 @@ def today?
time.today?
end

# Returns true if the current object's time falls within
# the next day (tomorrow).
def tomorrow?
time.tomorrow?
end
alias :next_day? :tomorrow?

# Returns true if the current object's time falls within
# the previous day (yesterday).
def yesterday?
time.yesterday?
end
alias :prev_day? :yesterday?

# Returns true if the current object's time is in the future.
def future?
utc.future?
Expand Down
74 changes: 73 additions & 1 deletion activesupport/test/core_ext/date_time_ext_test.rb
Expand Up @@ -253,9 +253,81 @@ def test_today_without_offset
end
end

def test_yesterday_with_offset
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal true, DateTime.civil(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)).yesterday?
assert_equal false, DateTime.civil(2000, 1, 1, 0, 0, 0, Rational(-18000, 86400)).yesterday?
assert_equal false, DateTime.civil(2000, 1, 1, 23, 59, 59, Rational(-18000, 86400)).yesterday?
assert_equal true, DateTime.civil(1999, 12, 31, 0, 0, 0, Rational(-18000, 86400)).yesterday?
end
end

def test_yesterday_without_offset
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal true, DateTime.civil(1999, 12, 31, 23, 59, 59).yesterday?
assert_equal false, DateTime.civil(2000, 1, 1, 0).yesterday?
assert_equal false, DateTime.civil(2000, 1, 1, 23, 59, 59).yesterday?
assert_equal false, DateTime.civil(2000, 1, 2, 0).yesterday?
end
end

def test_prev_day_with_offset
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal true, DateTime.civil(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)).prev_day?
assert_equal false, DateTime.civil(2000, 1, 1, 0, 0, 0, Rational(-18000, 86400)).prev_day?
assert_equal false, DateTime.civil(2000, 1, 1, 23, 59, 59, Rational(-18000, 86400)).prev_day?
assert_equal true, DateTime.civil(1999, 12, 31, 0, 0, 0, Rational(-18000, 86400)).prev_day?
end
end

def test_prev_day_without_offset
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal true, DateTime.civil(1999, 12, 31, 23, 59, 59).prev_day?
assert_equal false, DateTime.civil(2000, 1, 1, 0).prev_day?
assert_equal false, DateTime.civil(2000, 1, 1, 23, 59, 59).prev_day?
assert_equal false, DateTime.civil(2000, 1, 2, 0).prev_day?
end
end

def test_tomorrow_with_offset
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal false, DateTime.civil(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)).tomorrow?
assert_equal true, DateTime.civil(2000, 1, 2, 0, 0, 0, Rational(-18000, 86400)).tomorrow?
assert_equal false, DateTime.civil(2000, 1, 1, 23, 59, 59, Rational(-18000, 86400)).tomorrow?
assert_equal true, DateTime.civil(2000, 1, 2, 23, 59, 59, Rational(-18000, 86400)).tomorrow?
end
end

def test_tomorrow_without_offset
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal false, DateTime.civil(1999, 12, 31, 23, 59, 59).tomorrow?
assert_equal true, DateTime.civil(2000, 1, 2, 0).tomorrow?
assert_equal false, DateTime.civil(2000, 1, 1, 23, 59, 59).tomorrow?
assert_equal false, DateTime.civil(2000, 1, 3, 0).tomorrow?
end
end

def test_next_day_with_offset
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal false, DateTime.civil(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)).next_day?
assert_equal true, DateTime.civil(2000, 1, 2, 0, 0, 0, Rational(-18000, 86400)).next_day?
assert_equal false, DateTime.civil(2000, 1, 1, 23, 59, 59, Rational(-18000, 86400)).next_day?
assert_equal true, DateTime.civil(2000, 1, 2, 23, 59, 59, Rational(-18000, 86400)).next_day?
end
end

def test_next_day_without_offset
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal false, DateTime.civil(1999, 12, 31, 23, 59, 59).next_day?
assert_equal true, DateTime.civil(2000, 1, 2, 0).next_day?
assert_equal false, DateTime.civil(2000, 1, 1, 23, 59, 59).next_day?
assert_equal false, DateTime.civil(2000, 1, 3, 0).next_day?
end
end

def test_past_with_offset
DateTime.stub(:current, DateTime.civil(2005, 2, 10, 15, 30, 45, Rational(-18000, 86400))) do
assert_equal true, DateTime.civil(2005, 2, 10, 15, 30, 44, Rational(-18000, 86400)).past?
assert_equal true, DateTime.civil(2005, 2, 10, 15, 30, 44, Rational(-18000, 86400)).past?
assert_equal false, DateTime.civil(2005, 2, 10, 15, 30, 45, Rational(-18000, 86400)).past?
assert_equal false, DateTime.civil(2005, 2, 10, 15, 30, 46, Rational(-18000, 86400)).past?
end
Expand Down
72 changes: 72 additions & 0 deletions activesupport/test/core_ext/time_ext_test.rb
Expand Up @@ -686,6 +686,78 @@ def test_today_with_time_utc
end
end

def test_yesterday_with_time_local
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal true, Time.local(1999, 12, 31, 23, 59, 59).yesterday?
assert_equal false, Time.local(2000, 1, 1, 0).yesterday?
assert_equal true, Time.local(1999, 12, 31).yesterday?
assert_equal false, Time.local(2000, 1, 2, 0).yesterday?
end
end

def test_yesterday_with_time_utc
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal true, Time.utc(1999, 12, 31, 23, 59, 59).yesterday?
assert_equal false, Time.utc(2000, 1, 1, 0).yesterday?
assert_equal true, Time.utc(1999, 12, 31).yesterday?
assert_equal false, Time.utc(2000, 1, 2, 0).yesterday?
end
end

def test_prev_day_with_time_local
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal true, Time.local(1999, 12, 31, 23, 59, 59).prev_day?
assert_equal false, Time.local(2000, 1, 1, 0).prev_day?
assert_equal true, Time.local(1999, 12, 31).prev_day?
assert_equal false, Time.local(2000, 1, 2, 0).prev_day?
end
end

def test_prev_day_with_time_utc
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal true, Time.utc(1999, 12, 31, 23, 59, 59).prev_day?
assert_equal false, Time.utc(2000, 1, 1, 0).prev_day?
assert_equal true, Time.utc(1999, 12, 31).prev_day?
assert_equal false, Time.utc(2000, 1, 2, 0).prev_day?
end
end

def test_tomorrow_with_time_local
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal false, Time.local(1999, 12, 31, 23, 59, 59).tomorrow?
assert_equal true, Time.local(2000, 1, 2, 0).tomorrow?
assert_equal true, Time.local(2000, 1, 2, 23, 59, 59).tomorrow?
assert_equal false, Time.local(2000, 1, 1, 0).tomorrow?
end
end

def test_tomorrow_with_time_utc
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal false, Time.utc(1999, 12, 31, 23, 59, 59).tomorrow?
assert_equal true, Time.utc(2000, 1, 2, 0).tomorrow?
assert_equal true, Time.utc(2000, 1, 2, 23, 59, 59).tomorrow?
assert_equal false, Time.utc(2000, 1, 1, 0).tomorrow?
end
end

def test_next_day_with_time_local
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal false, Time.local(1999, 12, 31, 23, 59, 59).next_day?
assert_equal true, Time.local(2000, 1, 2, 0).next_day?
assert_equal true, Time.local(2000, 1, 2, 23, 59, 59).next_day?
assert_equal false, Time.local(2000, 1, 1, 0).next_day?
end
end

def test_next_day_with_time_utc
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal false, Time.utc(1999, 12, 31, 23, 59, 59).next_day?
assert_equal true, Time.utc(2000, 1, 2, 0).next_day?
assert_equal true, Time.utc(2000, 1, 2, 23, 59, 59).next_day?
assert_equal false, Time.utc(2000, 1, 1, 0).next_day?
end
end

def test_past_with_time_current_as_time_local
with_env_tz "US/Eastern" do
Time.stub(:current, Time.local(2005, 2, 10, 15, 30, 45)) do
Expand Down
36 changes: 36 additions & 0 deletions activesupport/test/core_ext/time_with_zone_test.rb
Expand Up @@ -251,6 +251,42 @@ def test_today
end
end

def test_yesterday?
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal true, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(1999, 12, 31, 23, 59, 59)).yesterday?
assert_equal false, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2000, 1, 1, 0)).yesterday?
assert_equal true, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(1999, 12, 31)).yesterday?
assert_equal false, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2000, 1, 2, 0)).yesterday?
end
end

def test_prev_day?
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal true, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(1999, 12, 31, 23, 59, 59)).prev_day?
assert_equal false, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2000, 1, 1, 0)).prev_day?
assert_equal true, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(1999, 12, 31)).prev_day?
assert_equal false, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2000, 1, 2, 0)).prev_day?
end
end

def test_tomorrow?
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal false, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(1999, 12, 31, 23, 59, 59)).tomorrow?
assert_equal true, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2000, 1, 2, 0)).tomorrow?
assert_equal false, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2000, 1, 1, 23, 59, 59)).tomorrow?
assert_equal false, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(1999, 12, 31, 0)).tomorrow?
end
end

def test_next_day?
Date.stub(:current, Date.new(2000, 1, 1)) do
assert_equal false, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(1999, 12, 31, 23, 59, 59)).next_day?
assert_equal true, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2000, 1, 2, 0)).next_day?
assert_equal false, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2000, 1, 1, 23, 59, 59)).next_day?
assert_equal false, ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(1999, 12, 31, 0)).next_day?
end
end

def test_past_with_time_current_as_time_local
with_env_tz "US/Eastern" do
Time.stub(:current, Time.local(2005, 2, 10, 15, 30, 45)) do
Expand Down
4 changes: 2 additions & 2 deletions guides/source/active_support_core_extensions.md
Expand Up @@ -2928,7 +2928,7 @@ INFO: The following calculation methods have edge cases in October 1582, since d

#### `Date.current`

Active Support defines `Date.current` to be today in the current time zone. That's like `Date.today`, except that it honors the user time zone, if defined. It also defines `Date.yesterday` and `Date.tomorrow`, and the instance predicates `past?`, `today?`, `future?`, `on_weekday?` and `on_weekend?`, all of them relative to `Date.current`.
Active Support defines `Date.current` to be today in the current time zone. That's like `Date.today`, except that it honors the user time zone, if defined. It also defines `Date.yesterday` and `Date.tomorrow`, and the instance predicates `past?`, `today?`, `tomorrow?`, `next_day?`, `yesterday?`, `prev_day?`, `future?`, `on_weekday?` and `on_weekend?`, all of them relative to `Date.current`.

When making Date comparisons using methods which honor the user time zone, make sure to use `Date.current` and not `Date.today`. There are cases where the user time zone might be in the future compared to the system time zone, which `Date.today` uses by default. This means `Date.today` may equal `Date.yesterday`.

Expand Down Expand Up @@ -3441,7 +3441,7 @@ t.advance(seconds: 1)

#### `Time.current`

Active Support defines `Time.current` to be today in the current time zone. That's like `Time.now`, except that it honors the user time zone, if defined. It also defines the instance predicates `past?`, `today?`, and `future?`, all of them relative to `Time.current`.
Active Support defines `Time.current` to be today in the current time zone. That's like `Time.now`, except that it honors the user time zone, if defined. It also defines the instance predicates `past?`, `today?`, `tomorrow?`, `next_day?`, `yesterday?`, `prev_day?` and `future?`, all of them relative to `Time.current`.

When making Time comparisons using methods which honor the user time zone, make sure to use `Time.current` instead of `Time.now`. There are cases where the user time zone might be in the future compared to the system time zone, which `Time.now` uses by default. This means `Time.now.to_date` may equal `Date.yesterday`.

Expand Down

0 comments on commit 5df9b45

Please sign in to comment.