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
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
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
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.Next
— TypeNext(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
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)
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.
RDates.Previous
— TypePrevious(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
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)
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.