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.MonthIncrementPDOMType
MonthIncrementPDOM()

When incrementing by months (or years) then preserve the day of month from originally requested. Uses the "PDOM" shorthand

source
RDates.MonthIncrementPDOMEOMType
MonthIncrementPDOMEOM()
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.

source

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.InvalidDayLDOMType
InvalidDayLDOM()

When the day calculated is invalid, move to the last day of the month. Will use the "LDOM" short hand.

source
RDates.InvalidDayFDONMType
InvalidDayFDONM()

When the day calculated is invalid, move to the first day of the next month. Uses the "FDONM" short hand.

source
RDates.InvalidDayNDONMType
InvalidDayNDONM()

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.

source

We now have all the conventions we need to handle month and year adjustments

RDates.MonthType
Month(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
source
RDates.YearType
Year(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.

Note

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
source