Getting the third Friday of the month

Given a particular month, I need to find the third Friday of that month. I just found out that there is a function called dayofweekofmonth which basically does the reverse of what I want. You give it a date and it tells you that date is in fact the third Friday of the month (it returns 3).

For example, today is the second Monday of the month

julia> dayofweekofmonth(Date("2021-03-08"))
2

I basically want to know if there is a shorthand for the inverse of this function (as in, something that returns the date itself) or if anybody has a cute trick to come up with it beyond running a boolean check on every date inside a given month.

When I’ll have an access to my computer I’ll write full code, but idea is the following

  1. Calculate day of the week for the first day of the month e.g. “2021-03-01”
  2. Calculate the distance to the nearest Friday (number in range 0:6)
  3. Add 14
  4. Add result to the first day of the month

UPD:

function thirdfriday(dt)
    dt = floor(Date(dt), Month)
    dt |> dayofweek |> 
        (x -> 5 - x < 0 ? 12 - x : 5 - x) |> 
        (x -> x + 14) |> 
        (x -> dt + Day(x))
end

julia> dr = Date(2021):Month(1):Date(2022);
julia> thirdfriday.(dr)
13-element Vector{Date}:
 2021-01-15
 2021-02-19
 2021-03-19
 2021-04-16
 2021-05-21
 2021-06-18
 2021-07-16
 2021-08-20
 2021-09-17
 2021-10-15
 2021-11-19
 2021-12-17
 2022-01-21

It should be efficient, I suppose, since it adds no allocations, pure arithmetic.

It was interesting to read Dates documentation, there are interesting tonext and toprev functions as well as filter. So, if you are not afraid of iterations, at least they can be written in a very compact form

julia> tonext(x -> (dayofweek(x) == 5) && (dayofweekofmonth(x) == 3), Date("2020-03-01"))
2020-03-20

julia> dr = Date(2021):Day(1):Date(2022)
Date("2021-01-01"):Day(1):Date("2022-01-01")

julia> filter(dr) do x
           (dayofweek(x) == 5) && (dayofweekofmonth(x) == 3)
       end
12-element Vector{Date}:
 2021-01-15
 2021-02-19
 2021-03-19
 2021-04-16
 2021-05-21
 2021-06-18
 2021-07-16
 2021-08-20
 2021-09-17
 2021-10-15
 2021-11-19
 2021-12-17
5 Likes

Not sure this is particularly clever but here’s how I would do it:

julia> using Dates

julia> third_friday(dates) = dates[findfirst(x -> (dayofweek(x) == 5) && (dayofweekofmonth(x) == 3), dates)]
third_friday (generic function with 1 method)

julia> candidates = Date(2021,1,15):Day(1):Date(2021,1,21)
Date("2021-01-15"):Day(1):Date("2021-01-21")

julia> [third_friday(candidates + Month(i)) for i ∈ 0:12]
13-element Vector{Date}:
 2021-01-15
 2021-02-19
 2021-03-19
 2021-04-16
 2021-05-21
 2021-06-18
 2021-07-16
 2021-08-20
 2021-09-17
 2021-10-15
 2021-11-19
 2021-12-17
 2022-01-21

This uses the fact that the third Friday must be between the 15th and 21st (which I suppose is a variation on the “find first Friday and add 14” theme above)

1 Like

Here is another possibility:

function get_next_expiry(calc_date:: Date, month:: Integer; holidays:: AbstractArray = [])
    # get 3rd Wednesday of the corresponding month
    expiry_date = Dates.tonext(calc_date + Month(month-1)) do x
       Dates.dayofweek(x) == Dates.Friday && Dates.dayofweekofmonth(x) == 3
    end
    # move to next business day if the day is a holiday - not sure if you need this
    Dates.tonext(expiry_date, same=true) do x
        isbusday(x, holidays=holidays)
    end
end

# get the next 300 3rd Fridays, shifted to next business day if required
expiry_dates = get_next_expiry.(START_DATE, 1:300; holidays=target_holidays)
2 Likes

Thanks for the responses. Extra points for @lungben for thinking ahead about business days (but I need them for the Eurex trading calendar, not sure that is built-in anywhere).

For most products, Eurex uses Target holiday calendar. Not sure if there is a free source, but it is available in Bloomberg or Reuters.

1 Like

Thanks! I’ll take a look.

Have a look at BusinessDays.jl. This example uses an unexported function findweekday. Find the first business day (TARGET2) on or after the first Friday of January 2021.

julia> using BusinessDays, Dates

help?> BusinessDays.findweekday
  findweekday(weekday_target::Integer, yy::Integer, mm::Integer, occurrence::Integer, ascending::Bool) → Date

  Given a year yy and month mm, finds a date where a choosen weekday occurs.

  weekday_target values are declared in module Base.Dates:
  Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday = 1,2,3,4,5,6,7.

  If ascending is true, searches from the beginning of the month. If false,
  searches from the end of the month.

  If occurrence is 2 and weekday_target is Monday, searches the 2nd Monday of
  the given month, and so on.

julia> dow = Dates.Friday; y = 2021; m = 1; occurence = 1
1

julia> tobday(:TARGET2, BusinessDays.findweekday(dow, y, m, occurence, true))
2021-01-04

Ah I was aware of BusinessDays.jl but did not know about this function.