Skip to content

Commit

Permalink
Merge pull request #20213 from JuliaLang/tk/negatenegate
Browse files Browse the repository at this point in the history
Deprecate negate keyword argument in Dates adjuster API
  • Loading branch information
tkelman authored Jan 25, 2017
2 parents a5ff787 + 4feddef commit 0751779
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 62 deletions.
116 changes: 62 additions & 54 deletions base/dates/adjusters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ lastdayofquarter(dt::DateTime) = DateTime(lastdayofquarter(Date(dt)))
immutable DateFunction
f::Function
# validate boolean, single-arg inner constructor
function DateFunction(f::ANY, negate::Bool, dt::TimeType)
function DateFunction(f::ANY, dt::TimeType)
isa(f(dt), Bool) || throw(ArgumentError("Provided function must take a single TimeType argument and return true or false"))
return new(negate ? x -> !f(x)::Bool : f)
return new(f)
end
end
Base.show(io::IO, df::DateFunction) = println(io, df.f)
Expand All @@ -143,89 +143,97 @@ function adjust(df::DateFunction, start, step, limit)
throw(ArgumentError("Adjustment limit reached: $limit iterations"))
end

function adjust(func::Function, start; step::Period=Day(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, start), start, step, limit)
function adjust(func::Function, start; step::Period=Day(1), negate=nothing, limit::Int=10000)
func = deprecate_negate(:adjust, func, "func,start", negate)
return adjust(DateFunction(func, start), start, step, limit)
end

# Constructors using DateFunctions

"""
Date(f::Function, y[, m, d]; step=Day(1), negate=false, limit=10000) -> Date
Date(f::Function, y[, m, d]; step=Day(1), limit=10000) -> Date
Create a `Date` through the adjuster API. The starting point will be constructed from the
provided `y, m, d` arguments, and will be adjusted until `f::Function` returns `true`. The
step size in adjusting can be provided manually through the `step` keyword. If
`negate=true`, then the adjusting will stop when `f::Function` returns `false` instead of
`true`. `limit` provides a limit to the max number of iterations the adjustment API will
provided `y, m, d` arguments, and will be adjusted until `f::Function` returns `true`.
The step size in adjusting can be provided manually through the `step` keyword.
`limit` provides a limit to the max number of iterations the adjustment API will
pursue before throwing an error (given that `f::Function` is never satisfied).
"""
function Date(func::Function, y, m=1, d=1;step::Period=Day(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, Date(y, m, d)), Date(y, m, d), step, limit)
function Date(func::Function, y, m=1, d=1;step::Period=Day(1), negate=nothing, limit::Int=10000)
func = deprecate_negate(:Date, func, "func,y,m,d", negate)
return adjust(DateFunction(func, Date(y, m, d)), Date(y, m, d), step, limit)
end

"""
DateTime(f::Function, y[, m, d, h, mi, s]; step=Day(1), negate=false, limit=10000) -> DateTime
DateTime(f::Function, y[, m, d, h, mi, s]; step=Day(1), limit=10000) -> DateTime
Create a `DateTime` through the adjuster API. The starting point will be constructed from
the provided `y, m, d...` arguments, and will be adjusted until `f::Function` returns
`true`. The step size in adjusting can be provided manually through the `step` keyword. If
`negate=true`, then the adjusting will stop when `f::Function` returns `false` instead of
`true`. `limit` provides a limit to the max number of iterations the adjustment API will
`true`. The step size in adjusting can be provided manually through the `step` keyword.
`limit` provides a limit to the max number of iterations the adjustment API will
pursue before throwing an error (in the case that `f::Function` is never satisfied).
"""
DateTime(::Function, args...)

function DateTime(func::Function, y, m=1; step::Period=Day(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, DateTime(y, m)), DateTime(y, m), step, limit)
function DateTime(func::Function, y, m=1; step::Period=Day(1), negate=nothing, limit::Int=10000)
func = deprecate_negate(:DateTime, func, "func,y,m", negate)
return adjust(DateFunction(func, DateTime(y, m)), DateTime(y, m), step, limit)
end
function DateTime(func::Function, y, m, d; step::Period=Hour(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, DateTime(y)), DateTime(y, m, d), step, limit)
function DateTime(func::Function, y, m, d; step::Period=Hour(1), negate=nothing, limit::Int=10000)
func = deprecate_negate(:DateTime, func, "func,y,m,d", negate)
return adjust(DateFunction(func, DateTime(y)), DateTime(y, m, d), step, limit)
end
function DateTime(func::Function, y, m, d, h; step::Period=Minute(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, DateTime(y)), DateTime(y, m, d, h), step, limit)
function DateTime(func::Function, y, m, d, h; step::Period=Minute(1), negate=nothing, limit::Int=10000)
func = deprecate_negate(:DateTime, func, "func,y,m,d,h", negate)
return adjust(DateFunction(func, DateTime(y)), DateTime(y, m, d, h), step, limit)
end
function DateTime(func::Function, y, m, d, h, mi; step::Period=Second(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, DateTime(y)), DateTime(y, m, d, h, mi), step, limit)
function DateTime(func::Function, y, m, d, h, mi; step::Period=Second(1), negate=nothing, limit::Int=10000)
func = deprecate_negate(:DateTime, func, "func,y,m,d,h,mi", negate)
return adjust(DateFunction(func, DateTime(y)), DateTime(y, m, d, h, mi), step, limit)
end
function DateTime(func::Function, y, m, d, h, mi, s; step::Period=Millisecond(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, DateTime(y)), DateTime(y, m, d, h, mi, s), step, limit)
function DateTime(func::Function, y, m, d, h, mi, s; step::Period=Millisecond(1), negate=nothing, limit::Int=10000)
func = deprecate_negate(:DateTime, func, "func,y,m,d,h,mi,s", negate)
return adjust(DateFunction(func, DateTime(y)), DateTime(y, m, d, h, mi, s), step, limit)
end

"""
Time(f::Function, h[, mi, s, ms, us]; step=Second(1), negate=false, limit=10000) -> Time
Time(f::Function, h[, mi, s, ms, us]; step=Second(1), limit=10000) -> Time
Create a `Time` through the adjuster API. The starting point will be constructed from the
provided `h, mi, s, ms, us` arguments, and will be adjusted until `f::Function` returns `true`. The step
size in adjusting can be provided manually through the `step` keyword. If `negate=true`,
then the adjusting will stop when `f::Function` returns `false` instead of `true`. `limit`
provided `h, mi, s, ms, us` arguments, and will be adjusted until `f::Function` returns `true`.
The step size in adjusting can be provided manually through the `step` keyword. `limit`
provides a limit to the max number of iterations the adjustment API will pursue before
throwing an error (in the case that `f::Function` is never satisfied). Note that the default step
will adjust to allow for greater precision for the given arguments; i.e. if hour, minute, and second
arguments are provided, the default step will be `Millisecond(1)` instead of `Second(1)`.
"""
Time(::Function, args...)

function Time(func::Function, h, mi=0; step::Period=Second(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, Time(h, mi)), Time(h, mi), step, limit)
function Time(func::Function, h, mi=0; step::Period=Second(1), negate=nothing, limit::Int=10000)
func = deprecate_negate(:Time, func, "func,h,mi", negate)
return adjust(DateFunction(func, Time(h, mi)), Time(h, mi), step, limit)
end
function Time(func::Function, h, mi, s; step::Period=Millisecond(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, Time(h, mi, s)), Time(h, mi, s), step, limit)
function Time(func::Function, h, mi, s; step::Period=Millisecond(1), negate=nothing, limit::Int=10000)
func = deprecate_negate(:Time, func, "func,h,mi,s", negate)
return adjust(DateFunction(func, Time(h, mi, s)), Time(h, mi, s), step, limit)
end
function Time(func::Function, h, mi, s, ms; step::Period=Microsecond(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate,Time(h, mi, s, ms)),Time(h, mi, s, ms), step, limit)
function Time(func::Function, h, mi, s, ms; step::Period=Microsecond(1), negate=nothing, limit::Int=10000)
func = deprecate_negate(:Time, func, "func,h,mi,s,ms", negate)
return adjust(DateFunction(func, Time(h, mi, s, ms)), Time(h, mi, s, ms), step, limit)
end
function Time(func::Function, h, mi, s, ms, us; step::Period=Nanosecond(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, Time(h, mi, s, ms, us)), Time(h, mi, s, ms, us), step, limit)
function Time(func::Function, h, mi, s, ms, us; step::Period=Nanosecond(1), negate=nothing, limit::Int=10000)
func = deprecate_negate(:Time, func, "func,h,mi,s,ms,us", negate)
return adjust(DateFunction(func, Time(h, mi, s, ms, us)), Time(h, mi, s, ms, us), step, limit)
end

# Return the next TimeType that falls on dow
ISDAYOFWEEK = Dict(Mon => DateFunction(ismonday, false, Date(0)),
Tue => DateFunction(istuesday, false, Date(0)),
Wed => DateFunction(iswednesday, false, Date(0)),
Thu => DateFunction(isthursday, false, Date(0)),
Fri => DateFunction(isfriday, false, Date(0)),
Sat => DateFunction(issaturday, false, Date(0)),
Sun => DateFunction(issunday, false, Date(0)))
ISDAYOFWEEK = Dict(Mon => DateFunction(ismonday, Date(0)),
Tue => DateFunction(istuesday, Date(0)),
Wed => DateFunction(iswednesday, Date(0)),
Thu => DateFunction(isthursday, Date(0)),
Fri => DateFunction(isfriday, Date(0)),
Sat => DateFunction(issaturday, Date(0)),
Sun => DateFunction(issunday, Date(0)))

# "same" indicates whether the current date can be considered or not
"""
Expand All @@ -239,15 +247,15 @@ tonext(dt::TimeType, dow::Int; same::Bool=false) = adjust(ISDAYOFWEEK[dow], same

# Return the next TimeType where func evals true using step in incrementing
"""
tonext(func::Function,dt::TimeType;step=Day(1),negate=false,limit=10000,same=false) -> TimeType
tonext(func::Function,dt::TimeType;step=Day(1),limit=10000,same=false) -> TimeType
Adjusts `dt` by iterating at most `limit` iterations by `step` increments until `func`
returns `true`. `func` must take a single `TimeType` argument and return a `Bool`. `same`
allows `dt` to be considered in satisfying `func`. `negate` will make the adjustment process
terminate when `func` returns `false` instead of `true`.
allows `dt` to be considered in satisfying `func`.
"""
function tonext(func::Function, dt::TimeType;step::Period=Day(1), negate::Bool=false, limit::Int=10000, same::Bool=false)
return adjust(DateFunction(func, negate, dt), same ? dt : dt+step, step, limit)
function tonext(func::Function, dt::TimeType;step::Period=Day(1), negate=nothing, limit::Int=10000, same::Bool=false)
func = deprecate_negate(:tonext, func, "func,dt", negate)
return adjust(DateFunction(func, dt), same ? dt : dt+step, step, limit)
end

"""
Expand All @@ -260,15 +268,15 @@ Tuesday, etc`. Setting `same=true` allows the current `dt` to be considered as t
toprev(dt::TimeType, dow::Int; same::Bool=false) = adjust(ISDAYOFWEEK[dow], same ? dt : dt+Day(-1), Day(-1), 7)

"""
toprev(func::Function,dt::TimeType;step=Day(-1),negate=false,limit=10000,same=false) -> TimeType
toprev(func::Function,dt::TimeType;step=Day(-1),limit=10000,same=false) -> TimeType
Adjusts `dt` by iterating at most `limit` iterations by `step` increments until `func`
returns `true`. `func` must take a single `TimeType` argument and return a `Bool`. `same`
allows `dt` to be considered in satisfying `func`. `negate` will make the adjustment process
terminate when `func` returns `false` instead of `true`.
allows `dt` to be considered in satisfying `func`.
"""
function toprev(func::Function, dt::TimeType; step::Period=Day(-1), negate::Bool=false, limit::Int=10000, same::Bool=false)
return adjust(DateFunction(func, negate, dt), same ? dt : dt+step, step, limit)
function toprev(func::Function, dt::TimeType; step::Period=Day(-1), negate=nothing, limit::Int=10000, same::Bool=false)
func = deprecate_negate(:toprev, func, "func,dt", negate)
return adjust(DateFunction(func, dt), same ? dt : dt+step, step, limit)
end

# Return the first TimeType that falls on dow in the Month or Year
Expand Down
18 changes: 17 additions & 1 deletion base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1766,7 +1766,7 @@ end
# Not exported
eval(LibGit2, quote
function owner(x)
depwarn("owner(x) is deprecated, use repository(x) instead.", :owner)
Base.depwarn("owner(x) is deprecated, use repository(x) instead.", :owner)
repository(x)
end
end)
Expand All @@ -1786,4 +1786,20 @@ function colon{T<:Dates.Period}(start::T, stop::T)
colon(start, T(1), stop)
end

# when this deprecation is deleted, remove all calls to it, and all
# negate=nothing keyword arguments, from base/dates/adjusters.jl
eval(Dates, quote
function deprecate_negate(f, func, sig, negate)
if negate === nothing
return func
else
msg = "$f($sig; negate=$negate) is deprecated, use $f("
negate && (msg *= "!")
msg *= "$sig) instead."
Base.depwarn(msg, f)
return negate ? !func : func
end
end
end)

# End deprecations scheduled for 0.6
11 changes: 6 additions & 5 deletions test/dates/adjusters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ dt = Dates.Date(2014,5,21)

@test Dates.tonext(Dates.Date(0),Dates.Mon) == Dates.Date(0,1,3)

#test func, diff steps, negate, same
#test func, diff steps, same
@test Dates.tonext(Dates.iswednesday,dt) == Dates.Date(2014,5,28)
@test Dates.tonext(Dates.iswednesday,dt;same=true) == dt
@test Dates.tonext(Dates.isthursday,dt) == Dates.Date(2014,5,22)
Expand All @@ -240,7 +240,8 @@ dt = Dates.Date(2014,5,21)
@test Dates.tonext(Dates.istuesday,dt) == Dates.Date(2014,5,27)
@test Dates.tonext(Dates.ismonday,Dates.Date(0)) == Dates.Date(0,1,3)

@test Dates.tonext(x->!Dates.iswednesday(x),dt;negate=true) == Dates.Date(2014,5,28)
@test Dates.tonext(!Dates.iswednesday,dt) == Dates.Date(2014,5,22)
@test Dates.tonext(!Dates.isthursday,dt) == Dates.Date(2014,5,23)
# Reach adjust limit
@test_throws ArgumentError Dates.tonext(Dates.iswednesday,dt;limit=6)

Expand Down Expand Up @@ -322,8 +323,8 @@ Januarymondays2014 = [Dates.Date(2014,1,6),Dates.Date(2014,1,13),Dates.Date(2014
@test filter(Dates.ismonday,startdate:stopdate) == Januarymondays2014

@test_throws MethodError filter((x,y)->x+y,Dates.Date(2013):Dates.Date(2014))
@test_throws MethodError Dates.DateFunction((x,y)->x+y, false, Date(0))
@test_throws ArgumentError Dates.DateFunction((dt)->2, false, Date(0))
@test_throws MethodError Dates.DateFunction((x,y)->x+y, Date(0))
@test_throws ArgumentError Dates.DateFunction((dt)->2, Date(0))
@test length(filter(x->true,Dates.Date(2013):Dates.Date(2013,2))) == 32
@test length(filter(x->true,Dates.Date(2013):Dates.Date(2013,1,1))) == 1
@test length(filter(x->true,Dates.Date(2013):Dates.Date(2013,1,2))) == 2
Expand Down Expand Up @@ -469,4 +470,4 @@ r = Dates.Time(x->Dates.second(x) == 5, 1)
r = filter(x->Dates.second(x) == 5, Dates.Time(0):Dates.Time(10))
@test length(r) == 600
@test first(r) == Dates.Time(0,0,5)
@test last(r) == Dates.Time(9,59,5)
@test last(r) == Dates.Time(9,59,5)
4 changes: 2 additions & 2 deletions test/dates/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -536,5 +536,5 @@ a = Dates.Time(23,1,1)
@test map(x->a in x,drs[1:4]) == [true,true,false,true]
@test a in dr

@test all(x->sort(x) == (step(x) < zero(step(x)) ? reverse(x) : x),drs)
@test all(x->step(x) < zero(step(x)) ? issorted(reverse(x)) : issorted(x),drs)
@test all(x->sort(x) == (step(x) < zero(step(x)) ? reverse(x) : x), drs)
@test all(x->step(x) < zero(step(x)) ? issorted(reverse(x)) : issorted(x), drs)

0 comments on commit 0751779

Please sign in to comment.