Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@joewiz
Last active November 18, 2021 15:59
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joewiz/ad1e370ecb6c19feedbf4804f76268d7 to your computer and use it in GitHub Desktop.
Save joewiz/ad1e370ecb6c19feedbf4804f76268d7 to your computer and use it in GitHub Desktop.
Second Tuesdays of the year, with XQuery

Today in exist-open, Slav asked:

Hi, anyone have function for calculate all second Tuesdays for year?

(That is, Patch Tuesdays.)

Below are two approaches—one that solves the problem directly (finding only 2nd Tuesdays) and one more generally (finding any combination of week of the month and day of the week, e.g., 5th Sundays).

xquery version "3.1";
(: A basic approach to finding the 2nd Tuesdays in a year :)
import module namespace functx = "http://www.functx.com";
(:~ List the dates of all 2nd Tuesdays in a year
:
: @param $year A year
: @return Dates
:
: @see http://www.xqueryfunctions.com/xq/functx_date.html
: @see http://www.xqueryfunctions.com/xq/functx_day-of-week.html
:)
declare function local:second-tuesdays($year as xs:string) as xs:date+ {
for $month in 1 to 12
for $day in 8 to 14
let $date := functx:date($year, $month, $day)
return
if (functx:day-of-week($date) eq 2) then
$date
else
()
};
local:second-tuesdays("2021")
(
xs:date("2021-01-12"),
xs:date("2021-02-09"),
xs:date("2021-03-09"),
xs:date("2021-04-13"),
xs:date("2021-05-11"),
xs:date("2021-06-08"),
xs:date("2021-07-13"),
xs:date("2021-08-10"),
xs:date("2021-09-14"),
xs:date("2021-10-12"),
xs:date("2021-11-09"),
xs:date("2021-12-14")
)
xquery version "3.1";
(: A more generalized approach to finding the 2nd Tuesdays in a year :)
import module namespace functx = "http://www.functx.com";
(:~ List the dates of any day in the week in a week in a month (e.g., 5th Sundays) between two dates
:
: @param $start-date The start date (inclusive)
: @param $end-date The end date (inclusive)
: @param $week-of-month The nth week of the month, as 1-5
: @param $day-of-week The day of the week, as 0-6 (0 = Sunday)
: @return Dates meeting criteria
:
: @see http://www.xqueryfunctions.com/xq/functx_days-in-month.html
: @see http://www.xqueryfunctions.com/xq/functx_date.html
: @see http://www.xqueryfunctions.com/xq/functx_day-of-week.html
:)
declare function local:nth-weekdays(
$start-date as xs:date,
$end-date as xs:date,
$week-of-month as xs:integer,
$day-of-week as xs:integer
) as xs:date* {
let $start-year := year-from-date($start-date)
let $end-year := year-from-date($end-date)
let $start-month := month-from-date($start-date)
let $end-month := month-from-date($end-date)
for $year in $start-year to $end-year
let $months :=
if ($year eq $start-year and $year eq $end-year) then
$start-month to $end-month
else if ($year eq $start-year) then
$start-month to 12
else if ($year eq $end-year) then
1 to $end-month
else
1 to 12
for $month in $months
let $days-in-month := functx:days-in-month(functx:date($year, $month, 1))
let $day-offset := 7 * ($week-of-month - 1) + 1
for $day in ($day-offset to ($day-offset + 6))[. le $days-in-month]
let $date := functx:date($year, $month, $day)
where $date ge $start-date and $date le $end-date
return
if (functx:day-of-week($date) eq $day-of-week) then
$date
else
()
};
(:~ List the dates of all 2nd Tuesdays in a year
:
: @param $year A year
: @returns Dates
:)
declare function local:second-tuesdays($year as xs:string) {
let $start-date := xs:date($year || "-01-01")
let $end-date := xs:date($year || "-12-31")
let $week-of-month := 2
let $day-of-week := 2
return
local:nth-weekdays($start-date, $end-date, $week-of-month, $day-of-week)
};
local:second-tuesdays("2021")
(
xs:date("2021-01-12"),
xs:date("2021-02-09"),
xs:date("2021-03-09"),
xs:date("2021-04-13"),
xs:date("2021-05-11"),
xs:date("2021-06-08"),
xs:date("2021-07-13"),
xs:date("2021-08-10"),
xs:date("2021-09-14"),
xs:date("2021-10-12"),
xs:date("2021-11-09"),
xs:date("2021-12-14")
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment