Combinations

One of the key features of RDates is to allow us to combine primitive operations to provide a generalised method to describe date adjustments.

Negation

All our primitive operations provide a negative operation, which is achieved by applying the - operator to the RDate.

julia> Date(2019,1,1) - RDates.Day(1)
2018-12-31
julia> -RDates.Week(3) + Date(2019,1,1)
2018-12-11
Note

While all our RDates support negation, they may not have an effect and will just return itself.

julia> -rd"1st WED" == rd"1st WED"
true

Addition

All RDates can be combined together via addition. The components are applied from left to right.

julia> rd"1d + 1y" + Date(2019,1,1)
2020-01-02
julia> rd"1MAR + 3rd WED" + Date(2019,1,1)
2019-03-20
Note

Where possible, addition operations may be optimised to reduce down to simpler state. This will always be done in a way in which we maintain the expected behaviour.

julia> rd"1d + 1d" == rd"2d"
true
Warning

The alegbra of month addition is not always straight forward. Make sure you're clear on exactly what you want to achieve.

julia> rd"2m" + Date(2019,1,31)
2019-03-31
julia> rd"1m + 1m" + Date(2019,1,31)
2019-03-28

Multiplication and Repeats

Every RDate supports multiplication and this will usually multiply it's underlying count. For most primitives this is completely understandable due to the inherent link between addition and multiplication.

julia> RDates.Day(2) * 5
10d
julia> RDates.Week(2) * -5
-10w

For RDates which do not have a natural count then the multiplication will just return itself

julia> 10 * RDates.NthWeekdays(:MON, 1)
1st MON

However when we come to handling months (and by extension years, though in rarer cases) we need to be more careful. We set a convention that multiplication is equivalent to multiplication of the internal count and so we won't get the same result as adding it n times.

julia> 2 * RDates.Month(1)
2m[LDOM;PDOM]
julia> rd"2 * 1m"
2m[LDOM;PDOM]
julia> 2 * RDates.Month(1) + Date(2019,1,31)
2019-03-31
julia> RDates.Month(1) + RDates.Month(1) + Date(2019,1,31)
2019-03-28

It may be though that you want that handling and so we introduce the Repeat operator to support that. This operator will repeat the application of the internalised rdate, rather than passing the multiplier through.

julia> 2 * RDates.Repeat(RDates.Month(1))
2*Repeat(1m[PDOM;LDOM])
julia> 2 * RDates.Repeat(RDates.Month(1)) + Date(2019,1,31)
2019-03-28
julia> rd"2*Repeat(1m)" + Date(2019,1,31)
2019-03-28

Other Operators

RDates.NextType
Next(parts, inclusive::Bool = false)

Next is a mechanism through which we can find the next closest date in the future, given a list of rdates to apply. We can choose whether today is also deemed a valid date.

This is commonly used in conjunction with rdates which don't necessarily always give a date in the future, such as asking for the next Easter from today.

Examples

julia> RDates.Next([RDates.Easter(0), RDates.Easter(1)]) + Date(2019,1,1)
2019-04-21
julia> rd"Next(0E,1E)" + Date(2019,1,1)
2019-04-21
julia> RDates.Next([RDates.Easter(0), RDates.Easter(1)]) + Date(2019,4,21)
2020-04-12
julia> RDates.Next([RDates.Easter(0), RDates.Easter(1)], true) + Date(2019,4,21)
2019-04-21
julia> rd"Next!(0E,1E)" + Date(2019,4,21)
2019-04-21
Note

The negation of Next will actually produce a Previous.

julia> -rd"Next(1d,2d)"
Previous(-1d, -2d)
julia> -3 * rd"Next(1d,2d)"
Previous(-3d, -6d)
Warning

While Next is a powerful operator, it does require application of every rdate every time, so can be expensive.

When combining with ranges, it can often be useful to use an appropriate pivot point to start from instead.

source
RDates.PreviousType
Previous(parts, inclusive::Bool = false)

Previous is a mechanism through which we can find the next closest date in the past, given a list of rdates to apply. We can choose whether today is also deemed a valid date.

This is commonly used in conjunction with rdates which don't necessarily always give a date in the future, such as asking for the previous Easter from today.

Examples

julia> RDates.Previous([RDates.Easter(0), RDates.Easter(-1)]) + Date(2019,12,31)
2019-04-21
julia> rd"Previous(0E,-1E)" + Date(2019,12,31)
2019-04-21
julia> RDates.Previous([RDates.Easter(0), RDates.Easter(-1)]) + Date(2019,4,21)
2018-04-01
julia> RDates.Previous([RDates.Easter(0), RDates.Easter(-1)], true) + Date(2019,4,21)
2019-04-21
julia> rd"Previous!(0E,-1E)" + Date(2019,4,21)
2019-04-21
Note

The negation of Previous will actually produce a Next.

julia> -rd"Previous(-1d,-2d)"
Next(1d, 2d)
julia> -3 * rd"Previous(-1d,-2d)"
Next(3d, 6d)
Warning

While Previous is a powerful operator, it does require application of every rdate every time, so can be expensive.

When combining with ranges, it can often be useful to use an appropriate pivot point to start from instead.

source