Find the nearest Date, given a TargetDate and Day of Week
Perl 6, 83 bytes
->$_,\w{~(Date.new(|m/(....)(..)(..)/)-3...*.day-of-week%7+1==w)[*-1]~~{S:g/"-"//}}
Try it
Expanded
-> # pointy block lambda
$_,
\w
{
~( # turn into a Str
Date.new( |m/(....)(..)(..)/ ) - 3 # three days earlier
... # generate a sequence
*.day-of-week % 7 + 1 == w # stop when the right day is found
)[*-1] # the last one
~~ # apply the following block
{
S:g/"-"// # remove 「-」
}
}
JavaScript (ES6), 93 bytes
(s,n,d=new Date(s))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toISOString().slice(0,10)
Uses %Y-%m-%d
date format. If %a %b %d %Y
is an acceptable date format, then for 82 bytes:
(s,n,d=new Date(s))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toDateString()
I could save a further 2 bytes by requiring Sunday = 10 to Saturday = 16, but that's a silly day of week mapping. Previous 142 141 bytes (thanks to @Guedes) version that used the specific YYYYMMDD date format, with its explanation:
(s,n,d=new Date(s.replace(/(?=..(..)?$)/g,'-')))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toISOString().replace(/-(..)-(..).*/,'$1$2')
This feels far too long. Explanation: First, inserts -
s into the date to get it into ISO format which new Date
can then parse. Then, compares the desired day with the actual day to get a value between -3
and 3
for the actual offset. The magic 9
comes from 7
(because %
is CPU modulo, not true modulo) plus 3
(for the -3
offset) minus 1
(because n
is 1-indexed and getDay
is 0-indexed). The date is then converted back into ISO format and the unwanted characters removed.