Months and Years
Adding months to a date is a surprisingly complex operation and so we've created a dedicated page to go through the details. For example
- What should happen if I add one month to the 31st January?
- Should adding one month to the 30th April maintain the end of month?
Years are less complex, but still suffer from the same edge case due to leap years and the 29th February. As such, we incorporate the same conventions.
To give us the level of flexibility, we need to introduce two conventions to support us.
Month Increment Convention
When we add a month to a date, we need to determine what we should do with the day. Most of the time we'll maintain the same day, but sometimes we may want to maintain the last day of the month, which is a common feature in financial contracts.
RDates.MonthIncrementPDOM
— TypeMonthIncrementPDOM()
When incrementing by months (or years) then preserve the day of month from originally requested. Uses the "PDOM" shorthand
RDates.MonthIncrementPDOMEOM
— TypeMonthIncrementPDOMEOM()
MonthIncrementPDOMEOM(calendars)
When incrementing by months (or years) then preserve the day of month from originally requested, unless it's the last day of the month then maintain that. Uses the "PDOMEOM" short hand.
To preserve the last business day of the month, then you can pass calendars as well.
Invalid Day Convention
The next convention we need is what to do if our increment leaves us on an invalid day of the month.
RDates.InvalidDayLDOM
— TypeInvalidDayLDOM()
When the day calculated is invalid, move to the last day of the month. Will use the "LDOM" short hand.
RDates.InvalidDayFDONM
— TypeInvalidDayFDONM()
When the day calculated is invalid, move to the first day of the next month. Uses the "FDONM" short hand.
RDates.InvalidDayNDONM
— TypeInvalidDayNDONM()
When the day calculated is invalid, move to the nth day of the next month where n is the number of days past the last day of the month. Uses the "NDONM" short hand.
We now have all the conventions we need to handle month and year adjustments
RDates.Month
— TypeMonth(months::Int64)
Month(months::Int64, idc::InvalidDayConvention, mic::MonthIncrementConvention)
Provides us with the ability to move a specified number of months, with conventions to handle how we should increment and what to do if we fall on an invalid day.
Examples
julia> RDates.Month(1) + Date(2019,1,31)
2019-02-28
julia> rd"1m" + Date(2019,1,31)
2019-02-28
julia> RDates.Month(1, RDates.InvalidDayFDONM(), RDates.MonthIncrementPDOM()) + Date(2019,1,31)
2019-03-01
julia> rd"1m[FDONM;PDOM]" + Date(2019,1,31)
2019-03-01
julia> RDates.Month(1, RDates.InvalidDayNDONM(), RDates.MonthIncrementPDOM()) + Date(2019,1,31)
2019-03-03
julia> rd"1m[NDONM;PDOM]" + Date(2019,1,31)
2019-03-03
julia> RDates.Month(1, RDates.InvalidDayNDONM(), RDates.MonthIncrementPDOMEOM()) + Date(2019,1,31)
2019-02-28
julia> rd"1m[NDONM;PDOMEOM]" + Date(2019,1,31)
2019-02-28
julia> RDates.Month(-1, RDates.InvalidDayNDONM(), RDates.MonthIncrementPDOMEOM()) + Date(2019,2,28)
2019-01-31
julia> rd"-1m[NDONM;PDOMEOM]" + Date(2019,2,28)
2019-01-31
RDates.Year
— TypeYear(years::Int64)
Year(years::Int64, idc::InvalidDayConvention, mic::MonthIncrementConvention)
Provides us with the ability to move a specified number of months, with conventions to handle how we should increment and what to do if we fall on an invalid day.
While these conventions are necessary, it's only around the handling of leap years and when we're on the last day of the February that it actually matters.
Examples
julia> RDates.Year(1) + Date(2019,2,28)
2020-02-28
julia> rd"1y" + Date(2019,2,28)
2020-02-28
julia> RDates.Year(1, RDates.InvalidDayFDONM(), RDates.MonthIncrementPDOMEOM()) + Date(2019,2,28)
2020-02-29
julia> rd"1y[FDONM;PDOMEOM]" + Date(2019,2,28)
2020-02-29
julia> RDates.Year(1, RDates.InvalidDayLDOM(), RDates.MonthIncrementPDOM()) + Date(2020,2,29)
2021-02-28
julia> rd"1y[LDOM;PDOM]" + Date(2020,2,29)
2021-02-28
julia> RDates.Year(1, RDates.InvalidDayFDONM(), RDates.MonthIncrementPDOM()) + Date(2020,2,29)
2021-03-01
julia> rd"1y[FDONM;PDOM]" + Date(2020,2,29)
2021-03-01