From 157d8f8259563514e90d6ce818b4befa96793c62 Mon Sep 17 00:00:00 2001 From: Gem Newman Date: Tue, 28 Jun 2016 09:36:42 -0500 Subject: [PATCH] Round to nonpositive resolution throws DomainError Throw DomainError on rounding to an invalid (non-positive) resolution Clean up test cases for rounding dates that don't need rounding Add test cases for rounding to invalid (non-positive) resolutions --- base/dates/rounding.jl | 5 +++++ test/dates/rounding.jl | 43 ++++++++++++++++-------------------------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/base/dates/rounding.jl b/base/dates/rounding.jl index 1ffbe586b7a387..e9a08c6fc13c28 100644 --- a/base/dates/rounding.jl +++ b/base/dates/rounding.jl @@ -38,11 +38,13 @@ Takes the given `DateTime` and returns the number of milliseconds since the roun datetime2epochms(dt::DateTime) = value(dt) - DATETIMEEPOCH function Base.floor(dt::Date, p::Year) + value(p) < 1 && throw(DomainError()) years = year(dt) return Date(years - mod(years, value(p))) end function Base.floor(dt::Date, p::Month) + value(p) < 1 && throw(DomainError()) y, m = yearmonth(dt) months_since_epoch = y * 12 + m - 1 month_offset = months_since_epoch - mod(months_since_epoch, value(p)) @@ -52,12 +54,14 @@ function Base.floor(dt::Date, p::Month) end function Base.floor(dt::Date, p::Week) + value(p) < 1 && throw(DomainError()) days = value(dt) - WEEKEPOCH days = days - mod(days, value(Day(p))) return Date(UTD(WEEKEPOCH + Int64(days))) end function Base.floor(dt::Date, p::Day) + value(p) < 1 && throw(DomainError()) days = date2epochdays(dt) return epochdays2date(days - mod(days, value(p))) end @@ -65,6 +69,7 @@ end Base.floor(dt::DateTime, p::DatePeriod) = DateTime(Base.floor(Date(dt), p)) function Base.floor(dt::DateTime, p::TimePeriod) + value(p) < 1 && throw(DomainError()) milliseconds = datetime2epochms(dt) return epochms2datetime(milliseconds - mod(milliseconds, value(Millisecond(p)))) end diff --git a/test/dates/rounding.jl b/test/dates/rounding.jl index 4cf852deb314d6..80218fcf0db472 100644 --- a/test/dates/rounding.jl +++ b/test/dates/rounding.jl @@ -111,33 +111,12 @@ dt = Dates.DateTime(-1, 12, 29, 19, 19, 19, 19) @test ceil(dt, Dates.Second(2)) == DateTime(-1, 12, 29, 19, 19, 20) # Test rounding for dates that should not need rounding -dt = Dates.DateTime(2016, 1, 1) -@test floor(dt, Dates.Year) == dt -@test floor(dt, Dates.Month) == dt -@test floor(dt, Dates.Day) == dt -@test floor(dt, Dates.Hour) == dt -@test floor(dt, Dates.Minute) == dt -@test floor(dt, Dates.Second) == dt -@test ceil(dt, Dates.Year) == dt -@test ceil(dt, Dates.Month) == dt -@test ceil(dt, Dates.Day) == dt -@test ceil(dt, Dates.Hour) == dt -@test ceil(dt, Dates.Minute) == dt -@test ceil(dt, Dates.Second) == dt - -dt = Dates.DateTime(-2016, 1, 1) -@test floor(dt, Dates.Year) == dt -@test floor(dt, Dates.Month) == dt -@test floor(dt, Dates.Day) == dt -@test floor(dt, Dates.Hour) == dt -@test floor(dt, Dates.Minute) == dt -@test floor(dt, Dates.Second) == dt -@test ceil(dt, Dates.Year) == dt -@test ceil(dt, Dates.Month) == dt -@test ceil(dt, Dates.Day) == dt -@test ceil(dt, Dates.Hour) == dt -@test ceil(dt, Dates.Minute) == dt -@test ceil(dt, Dates.Second) == dt +for dt in [Dates.DateTime(2016, 1, 1), Dates.DateTime(-2016, 1, 1)] + for p in [Dates.Year, Dates.Month, Dates.Day, Dates.Hour, Dates.Minute, Dates.Second] + @test floor(dt, p) == dt + @test ceil(dt, p) == dt + end +end # Test available RoundingModes dt = Dates.DateTime(2016, 2, 28, 12) @@ -148,3 +127,13 @@ dt = Dates.DateTime(2016, 2, 28, 12) @test_throws DomainError round(dt, Dates.Day, RoundNearestTiesAway) @test_throws DomainError round(dt, Dates.Day, RoundToZero) @test round(dt, Dates.Day) == round(dt, Dates.Day, RoundNearestTiesUp) + +# Test rounding to invalid resolutions +dt = Dates.DateTime(2016, 2, 28, 12, 15) +for p in [Dates.Year, Dates.Month, Dates.Week, Dates.Day, Dates.Hour] + for v in [-1, 0] + @test_throws DomainError floor(dt, p(v)) + @test_throws DomainError ceil(dt, p(v)) + @test_throws DomainError round(dt, p(v)) + end +end