Skip to content

Commit

Permalink
Round to nonpositive resolution throws DomainError
Browse files Browse the repository at this point in the history
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
  • Loading branch information
spurll committed Jun 28, 2016
1 parent 622b2c8 commit 157d8f8
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 27 deletions.
5 changes: 5 additions & 0 deletions base/dates/rounding.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -52,19 +54,22 @@ 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

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
Expand Down
43 changes: 16 additions & 27 deletions test/dates/rounding.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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

0 comments on commit 157d8f8

Please sign in to comment.