Introduction
Often, people refer to dates as the "second Friday in August, 2018" or the "fourth Sunday in March, 2012". But it's hard to tell what date that is! Your task to is to write a program that receives a year, a month, a day of the week, and an integer, and output that date.
Challenge
For input, you will get a year, a month, a day of week, and a number.
You can take input in any reasonable format, like using a string for the day of week or using a zero indexed weekday, or even take the year and month in a single string. Do explain your input format in your answer, though.
The integer that tells you which day of week in the month to target will be an integer from 1-5. The integer will never refer to a day of week that does not exist(e.g. the fifth Friday of February 2019, which doesn't exist).
Years will always be positive.
Your output can be in any reasonable format, including printing your final date. However, please explain your output format un your answer.
Providing the year and month in the output is optional. Also, you may assume the date is valid.
Example Input and Output
Consider this input, with the format being taking in the year as a 4 digit number, month as an integer, day of week as string, and the ordinal number as an integer:
2019, 3, Saturday, 2
2019, 12, Sunday, 1
2019, 9 Saturday, 1
Output:
March 9
December 1
September 7
This is code-golf, so shortest answer wins.
17 Answers 17
MediaWiki Template, 19 bytes
{{#time:r|{{{1}}}}}
This is a MediaWiki Template ParserFunctions port of this PHP answer
Note: #time use PHP strtotime internally.
Sample Input
{{#time:r|second saturday of March 2019}}
Sample Output
2019年3月09日 00:00:00 +0000
Japt, (削除) 19 (削除ここまで) 15 bytes
Input is: year, 0-based index of month, 0-based index of day of the week (0 is Sunday) & n.
_XμW¶Ze}f@ÐUVYÄ
:Implicit input of U=year, V=month, W=weekday & X=n
}f :Output the first element generated by the right function that returns
: falsey (0) when passed through the left function
@ :Right function. Y=0-based index of current iteration
ÐUVYÄ : new Date(U,V,Y+1)
_ :Left function. Z=date being passed
Xμ : Decrement X by
W¶ : Test W for equality with
Ze : Z.getDay()
Perl 6, (削除) 52 (削除ここまで) 48 bytes
{1+($^c+4-Date.new($^a,$^b,1).daycount)%7+$^d*7}
Anonymous code block that takes input as year, month, day of week (Sunday is 0) and week number (0 indexed). Output is a date object.
Old Explanation:
{ } # Anonymous code block
( Date.new( )) # Create a new date with
$^a,$^b,1 # With year, month and the first day
$_= # Save in the variable $_
+ # Add to this
$^c+4 # The given day plus 4
( -.daycount) # The number of days since 17 Nov, 1858
%7 # Modulo 7 to get the correct day
+$^d*7 # Plus the 7 times the number of weeks
-
\$\begingroup\$ I think the week number needs to be 1-indexed \$\endgroup\$12Me21– 12Me212019年01月02日 01:37:34 +00:00Commented Jan 2, 2019 at 1:37
-
\$\begingroup\$ @12Me21 The question says that input is flexible, but I've asked whether we an take week number as 0 indexed \$\endgroup\$Jo King– Jo King2019年01月02日 01:55:12 +00:00Commented Jan 2, 2019 at 1:55
-
\$\begingroup\$ This doesn't seem to work for other months. I think you need
$^c+4-$!.daycount. \$\endgroup\$nwellnhof– nwellnhof2019年01月02日 02:24:08 +00:00Commented Jan 2, 2019 at 2:24 -
\$\begingroup\$ @nwellnhof Ah, I should have thought of that instead of trial and error, lol. Should be fixed now \$\endgroup\$Jo King– Jo King2019年01月02日 03:00:14 +00:00Commented Jan 2, 2019 at 3:00
PHP, (削除) 46 (削除ここまで), (削除) 43 (削除ここまで), 31 bytes
<?=date(d,strtotime($argv[1]));
The program receives as input a string like "second saturday of March 2019"
The program prints the day number.
-12 bytes thanks to Shaggy.
-
1
-
\$\begingroup\$ Also, I don't think you need the
ofin the input. \$\endgroup\$Shaggy– Shaggy2019年01月01日 23:58:17 +00:00Commented Jan 1, 2019 at 23:58 -
\$\begingroup\$ @Shaggy, I think these are details. There may be many options. \$\endgroup\$Кирилл Малышев– Кирилл Малышев2019年01月02日 00:00:41 +00:00Commented Jan 2, 2019 at 0:00
C# (Visual C# Interactive Compiler), 59 bytes
(y,m,d,w)=>1+(d-(int)new DateTime(y,m,1).DayOfWeek+7)%7+7*w
-27 bytes thanks to @EmbodimentOfIgnorance!
Less golfed code...
// y: year
// m: month
// d: day of week (0 is Sunday)
// w: week number (0 based)
(y,m,d,w)=>
// start on the first day of the month
1+
// determine the number of days to
// the first occurrence of the
// requested weekday
(d-(int)new DateTime(y,m,1).DayOfWeek+7)%7+
// add the number of requested weeks
7*w
The return value is an integer for the day of the month of the requested date.
-
-
\$\begingroup\$ Thanks for the tip again - (that's 2x today ;) I will update my answers. \$\endgroup\$dana– dana2019年01月02日 04:14:30 +00:00Commented Jan 2, 2019 at 4:14
SmileBASIC, (削除) 58 (削除ここまで) (削除) 51 (削除ここまで) (削除) 48 (削除ここまで) (削除) 46 (削除ここまで) 45 bytes
READ N,M$DTREAD M$OUT,,D,W?(5-W+D*2)MOD 7+N*7
Input is in the form: week,year/month/weekday
week: week number, 0-indexedyear: year, 4 digitsmonth: month (1-indexed), 2 digits0-paddedweekday: day of the week (1-indexed, 1=Sunday), 2 digits0-padded
Output is the day of the month, 0 indexed.
The 2nd Saturday in March 2019 would be 1,2019年03月07日 → 8 (March 9th)
Ungolfed
READ WEEK,M$
DTREAD M$ OUT ,,D,W
'Functions in SB can output multiple values using OUT.
'In this case, we don't need the first 2 values, so no variables are given.
PRINT (5-W+ D*2) MOD 7 +WEEK*7
Explanation
The input form was specifically chosen so that the year/month/weekday could be passed directly to DTREAD, which is a function which parses a YYYY/MM/DD string and returns the year/month/day as numbers, as well as calculating the day of the week.
However, notice that, where DTREAD expects the day of the month, we're giving it the day of the week instead. This complicates things, but also means that there are fewer input values and we don't need to add /01 to the end of the date string.
DTREAD outputs W and D.
W is the weekday, and D is the day-of-the-week of the Wth day of the month.
(So, if you input 7 as the weekday, D will be 7 and W will be whatever day-of-the-week the 7th day of the month is)
The expression (5-W+D*2)MOD 7 is used to get the 1st occurrence of the input weekday, as a 0-indexed day of the month. (I figured this one out mostly through trial and error)
After that, the program just adds WEEK*7.
I really wish there were separate words for "day of the week" and "day of the month".
MATL, (削除) 28 (削除ここまで) 27 bytes
'1 'ihYO31:q+t8XOi=!A)i)1XO
This uses three inputs:
- String with month and year:
'March 2019' - String with three letters, first capitalized, indicating day of the week: '
Sat' - Number:
2.
Output is a string with day, year and month separated with dashes: 09-Mar-2019.
Explanation
Consider inputs 'March 2019', 'Sat', 2.
'1 ' % Push this string
% STACK: '1 '
ih % Input string: month and year. Concatenate
% STACK: '1 March 2019'
YO % Convert to serial date number
% STACK: 737485
31:q+ % Create vector [0 1 2 ... 30] and add element-wise
% STACK: [737485 737486 737487 ... 737515]
t8XO % Duplicate. Convert to date format 'ddd': day of week in three letters. Gives
% a 2D char array
% STACK: [737485 737486 737487 ... 737515], ['Fri'; 'Sat'; 'Sun'; ...; 'Sun']
i= % Input string: day of week in three letters. Compare element-wise with broadcast
% STACK: [737485 737486 737487 ... 737515],
% [0 0 0; 0 0 0; ...; 1 1 1; 0 0 0; ... 1 1 1; ...]
!A % True for rows containing only 1
% STACK: [737485 737486 737487 ... 737515], [0 0 ... 1 ... 0 ... 1 ...]
) % Index: uses the second vector as a mask into the first
% STACK: [737486 737493 737500 737507 737514]
i) % Input number. Index
% STACK: 737493
1XO % Convert to date format 'dd-mmm-yyyy'. Implicit display
% STACK: '09-Mar-2019'
Python 3, (削除) 92 (削除ここまで) 82 bytes
82 bytes thanks to @Jo King
lambda y,m,d,w:z(y,m)[w-(z(y,m)[0][d]>0)][d]
from calendar import*
z=monthcalendar
Original version, 92 bytes
from calendar import*
def f(y,m,d,w):
x=monthcalendar(y,m)
if x[0][d]:w-=1
return x[w][d]
Takes the year as an integer, month as a 1-indexed integer, day of the week as a 0-index integer where Monday is 0 and Sunday is 6, and week of the month as a 1-indexed integer.
How it works:
# import monthcalendar
from calendar import*
# function with 4 inputs
def f(y,m,d,w):
# get a 2-D array representing the specified month
# each week is represented by an array
# and the value of each element is its date of the month
# Monday is the 0th element of each week, Sunday is the 6th element
# days of the first week of the month before the 1st are 0s
x=monthcalendar(y,m)
# if the first week of the month includes the desired day of week
# convert the week of month to 0-index so that it takes into account the first week
if x[0][d]:w-=1
# return the weekday of the week number specified
return x[w][d]
R, (削除) 72 (削除ここまで) 69 bytes
function(y,m,d,n,D=as.Date(paste0(y,-m,-1))+0:31)D[weekdays(D)==d][n]
Taking input as :
- Year number
- Month number (1-12)
- Weekday string in the current locale (TIO requires english name with capital letter)
- Ordinal number (1-indexed)
Kotlin, (削除) 131 (削除ここまで) 84 bytes
47 bytes thanks to ASCII-only's code and comment.
Input: year, monthNumber, weekdayNumber, weekNumber
All integers 1 to maximum on single line. Week day number is Sunday of 1 to Saturday of 7. The main program makes the year lose 1900 for Date class and month and weekday are shifted to start with zero instead of one before calling the lambda. You can enter your arguments in the input text box to try your own dates.
Output: a Date class instance. The main program displays the result like: Sat Mar 09 00:00:00 UTC 2019.
There is an expanded version with comments explaining the code for those wishing to learn more.
{y,m,d,w->val r=java.util.Date(y,m,7*w)
r.setDate(r.getDate()-(r.getDay()+7-d)%7)
r}
-
1\$\begingroup\$ 74 - uses same method as Scala and Groovy answers \$\endgroup\$ASCII-only– ASCII-only2019年01月07日 04:30:30 +00:00Commented Jan 7, 2019 at 4:30
-
1\$\begingroup\$ Fixed, 84 \$\endgroup\$ASCII-only– ASCII-only2019年01月07日 04:35:46 +00:00Commented Jan 7, 2019 at 4:35
-
1\$\begingroup\$ No need for the import command anymore so that's not a problem :P \$\endgroup\$ASCII-only– ASCII-only2019年01月10日 09:31:20 +00:00Commented Jan 10, 2019 at 9:31
Groovy, 46 bytes
{y,m,d,w->r=new Date(y,m,7*w)
r-(r.day+7-d)%7}
Input as years since 1900, 0-indexed month, 0-indexed day (Sunday being 0) and week number
Scala, 86 bytes
(y,m,d,w)=>{var r=new java.util.Date(y,m,7*w)
r.setDate(r.getDate-(r.getDay+7-d)%7)
r}
Red, (削除) 64 (削除ここまで) 60 bytes
func[y m d n][a: to-date[1 m y]d - a/10 - 7 % 7 +(n * 7)+ a]
Takes the year, the month and the weekday as numbers, 1-indexed, Monday is the first day of the week.
-
\$\begingroup\$ huh,
to-dateis a thing. maybe this would be useful in the christmase eve format challenge \$\endgroup\$ASCII-only– ASCII-only2019年01月02日 09:18:40 +00:00Commented Jan 2, 2019 at 9:18 -
\$\begingroup\$ @ASCII-only We used
nowfor that challenge \$\endgroup\$Galen Ivanov– Galen Ivanov2019年01月02日 09:21:30 +00:00Commented Jan 2, 2019 at 9:21 -
1\$\begingroup\$ yeah, but i was thinking of alternative methods (namely, the <repeat
" Eve"date2-date1 times> method iirc) \$\endgroup\$ASCII-only– ASCII-only2019年01月02日 09:21:48 +00:00Commented Jan 2, 2019 at 9:21 -
\$\begingroup\$ @ASCII-only
>> 25-Dec-2019 -ひく 1-ひく1-ひく2019 =わ=わ 358\$\endgroup\$Galen Ivanov– Galen Ivanov2019年01月02日 09:24:01 +00:00Commented Jan 2, 2019 at 9:24
JavaScript (ES6), (削除) 49 (削除ここまで) 48 bytes
f=
(a,d,n)=>(d+6-new Date(...a,7).getDay())%7+n*7-6
<div oninput=o.textContent=f([+y.value,+m.value],+d.value,+n.value)>Year: <input id=y type=number value=2019><br>Month: <select id=m><option value=0>Jan<option value=1>Feb<option value=2>Mar<option value=3>Apr<option value=4>May<option value=5>Jun<option value=6>Jul<option value=7>Aug<option value=8>Sep<option value=9>Oct<option value=10>Nov<option value=11>Dec</select><br>Day: <select id=d><option value=0>Sun<option value=1>Mon<option value=2>Tue<option value=3>Wed<option value=4>Thu<option value=5>Fri<option value=6>Sat</select><br>Count: <input id=n type=number value=1 min=1 max=5><pre id=o>
Takes parameters as f([year, month], day, number). Month and day of week (starting on Sunday) are zero-indexed. Edit: Saved 1 byte thanks to @Shaggy.
-
\$\begingroup\$ Is the day of week in the format Sunday-Saturday or Monday-Sunday? \$\endgroup\$Gymhgy– Gymhgy2019年01月01日 22:48:18 +00:00Commented Jan 1, 2019 at 22:48
-
\$\begingroup\$ @EmbodimentofIgnorance Sorry, I knew I had forgotten something. (The snippet now uses select to make it easier.) \$\endgroup\$Neil– Neil2019年01月01日 22:51:12 +00:00Commented Jan 1, 2019 at 22:51
-
\$\begingroup\$ @EmbodimentofIgnorance, Sunday is
0in JS. \$\endgroup\$Shaggy– Shaggy2019年01月01日 22:52:03 +00:00Commented Jan 1, 2019 at 22:52 -
\$\begingroup\$ Oh. I didn't know that, I'm not that familiar with Javascript. \$\endgroup\$Gymhgy– Gymhgy2019年01月01日 22:52:36 +00:00Commented Jan 1, 2019 at 22:52
-
TSQL, 106 bytes
DECLARE @ datetime='2019',@m int=3,@w char(2)='saturday',@p int=2
SELECT dateadd(wk,datediff(d,x,dateadd(m,@m-1,@)-1)/7,x)+@p*7FROM(SELECT
charindex(@w,' tuwethfrsasu')/2x)x
Output:
2019年03月09日 00:00:00.000
APL (Dyalog Unicode), (削除) 36 (削除ここまで) 28 bytes SBCS
Full program. Prompts for [year,month] (January is 1), then for day (Sunday is 0), then for n (first is 1).
̄1⎕DT⎕⊃d/⍨⎕=7|d←(⍳31)+1⎕DT⊂⎕
⎕ prompt console for [year,month] numbers
1⎕DT⊂ days since 1899年12月31日 of the 0th of that month
(⍳31)+ add the integers 1...31 to that
d← store in d (for day numbers)
7| division remainder when dividing by 7 (day-of-week with Sunday being 0 due to good epoch)
⎕= prompt console for day-of-week number and get mask where equal the day-of-week numbers
d/⍨ filter d with that mask
⎕⊃ prompt console for n and use that to pick from the list of day numbers
̄1⎕DT datetime stamp (has trailing zeros for hours, minutes, seconds, milliseconds)
Go, 177 bytes
import."time"
func f(y,m,d string,n int)string{t,_:=Parse("20061",y+m)
D:=Hour*24
for t.Weekday().String()!=d{t=t.Add(D)}
for i:=1;i<n;i++{t=t.Add(D*7)}
return t.Format("Jan2")}
Outputs the month and the day as Jan2.
Explanation
import."time"
func f(y,m,d string,n int)string{
t,_:=Parse("20061",y+m)
Parse the date to get the first of the month. time.Date() is not feasible here because of the need for a location, which we don't need here.
D:=Hour*24
A time constant alias because Go doesn't provide time constants higher than Hour.
for t.Weekday().String()!=d{t=t.Add(D)}
Increment the day until we get the desired day.
for i:=1;i<n;i++{t=t.Add(D*7)}
Add weeks until we get the desired n-th day of the month.
return t.Format("Jan2")}
Return a string of the date, formatted as a 3-letter month and the date.
date, but amusingly, the parser has an... interesting interpretation here. \$\endgroup\$