Time difference in months/quarters/years

I’d like to calculate the number of periods between two dates. The aim is to calculate a loan amortizing schedule.

The following code arrives up to a certain point, i.e. to calculate the interval in days, but I’d like to convert those days in month, quarters or years as applicable. I’d use yearfrac and multiply it by a factor but I don’t find it easy to vectorize it.

using Dates, DayCounts
start_date = [Date(2022, 1, 1), Date(2021, 1, 1)]
maturity_date = [Date(2023, 1, 1), Date(2022, 12, 1)]
time_period = (Dates.value.(maturity_date) .- Dates.value.(start_date))

# or

time_period = yearfrac(start_date[1,1], maturity_date[1,1], DayCounts.Thirty360()) 

You can use Ref to treat values as scalars and exclude them from broadcast:

julia> time_period = yearfrac.(start_date, maturity_date, Ref(DayCounts.Thirty360()))
2-element Vector{Float64}:
 1.0
 1.9166666666666667
1 Like

@contradict has already provided you with a way to vectorize yearfrac.

An alternative is to compute the time difference in Days, as you did, and divide it by the period in Days:

julia> using Dates
julia> start_date = [Date(2022, 1, 1), Date(2021, 1, 1)];
julia> maturity_date = [Date(2023, 1, 1), Date(2022, 12, 1)];
julia> days_between = maturity_date .- start_date;
julia> months_between = days_between ./ Day(30)
2-element Vector{Float64}:
 12.166666666666666
 23.3

However, this way, you have to be precise about what you mean by a “period”, and take care of the rounding. For example, notice that the “number of months” (Day(30)) in a “year” (Day(365)) is not 12 this way.

Another way is to use ranges as proposed in https://discourse.julialang.org/t/number-of-months-between-two-dates/42128/3:

julia> [length(s:period:e) for (s, e) in zip(start_date, maturity_date)]
2-element Vector{Int64}:
 13
 24

But ranges are inclusive in julia, so for example:

julia> collect(Date(2022, 1, 1):Month(1):Date(2023, 1, 1))
13-element Vector{Date}:
 2022-01-01
 2022-02-01
 2022-03-01
 2022-04-01
 2022-05-01
 2022-06-01
 2022-07-01
 2022-08-01
 2022-09-01
 2022-10-01
 2022-11-01
 2022-12-01
 2023-01-01 # this is the maturity date

so you might want to subtract a Day(1) from the maturity dates.

Both are good answers, for the task of amortizing a pool of loans I ended up using this solution to avoid having to round yearfrac

n_periods = [length(s:Month((12/p)):e) for (s, p, e) in zip(start_date, frequency,maturity_date)].-1