20
\$\begingroup\$

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 , so shortest answer wins.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ I thought I might be able to use GNU date, but amusingly, the parser has an... interesting interpretation here. \$\endgroup\$
    – Doorknob
    Jan 1, 2019 at 20:44
  • \$\begingroup\$ May week number be 0-indexed? \$\endgroup\$
    – Jo King
    Jan 2, 2019 at 1:52
  • \$\begingroup\$ Sure, if it suits your program \$\endgroup\$
    – Gymhgy
    Jan 2, 2019 at 2:12
  • \$\begingroup\$ Suggested test case: 2018, 12, Sunday 1 \$\endgroup\$
    – Adám
    Jan 2, 2019 at 10:55
  • \$\begingroup\$ Suggested test case: the first Saturday in September 2019 \$\endgroup\$
    – Shaggy
    Jan 2, 2019 at 12:07

17 Answers 17

6
\$\begingroup\$

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

Sat, 09 Mar 2019 00:00:00 +0000

\$\endgroup\$
3
\$\begingroup\$

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Ä

Try it

                    :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()
\$\endgroup\$
3
\$\begingroup\$

Perl 6, 52 48 bytes

{1+($^c+4-Date.new($^a,$^b,1).daycount)%7+$^d*7}

Try it online!

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
\$\endgroup\$
4
  • \$\begingroup\$ I think the week number needs to be 1-indexed \$\endgroup\$
    – 12Me21
    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
    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
    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
    Jan 2, 2019 at 3:00
2
\$\begingroup\$

PHP, 46, 43, 31 bytes

<?=date(d,strtotime($argv[1]));

Try it online!

The program receives as input a string like "second saturday of March 2019"

The program prints the day number.

-12 bytes thanks to Shaggy.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ 31 bytes \$\endgroup\$
    – Shaggy
    Jan 1, 2019 at 23:42
  • \$\begingroup\$ Also, I don't think you need the of in the input. \$\endgroup\$
    – Shaggy
    Jan 1, 2019 at 23:58
  • \$\begingroup\$ @Shaggy, I think these are details. There may be many options. \$\endgroup\$ Jan 2, 2019 at 0:00
2
\$\begingroup\$

C# (Visual C# Interactive Compiler), 59 bytes

(y,m,d,w)=>1+(d-(int)new DateTime(y,m,1).DayOfWeek+7)%7+7*w

Try it online!

-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.

\$\endgroup\$
2
  • \$\begingroup\$ If you only return the day of the month, which is allowed, you can golf this down to 59 bytes \$\endgroup\$
    – Gymhgy
    Jan 2, 2019 at 3:04
  • \$\begingroup\$ Thanks for the tip again - (that's 2x today ;) I will update my answers. \$\endgroup\$
    – dana
    Jan 2, 2019 at 4:14
2
\$\begingroup\$

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-indexed
  • year: year, 4 digits
  • month: month (1-indexed), 2 digits 0-padded
  • weekday: day of the week (1-indexed, 1=Sunday), 2 digits 0-padded

Output is the day of the month, 0 indexed.
The 2nd Saturday in March 2019 would be 1,2019/03/078 (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".

\$\endgroup\$
1
\$\begingroup\$

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.

Try it online!

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'
\$\endgroup\$
1
\$\begingroup\$

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

Try it online!

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]

Try it online!

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]
\$\endgroup\$
0
1
\$\begingroup\$

R, 72 69 bytes

function(y,m,d,n,D=as.Date(paste0(y,-m,-1))+0:31)D[weekdays(D)==d][n]

Try it online!

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)
\$\endgroup\$
0
\$\begingroup\$

Groovy, 46 bytes

{y,m,d,w->r=new Date(y,m,7*w)
r-(r.day+7-d)%7}

Try it online!

Input as years since 1900, 0-indexed month, 0-indexed day (Sunday being 0) and week number

\$\endgroup\$
0
\$\begingroup\$

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}

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Red, 64 60 bytes

func[y m d n][a: to-date[1 m y]d - a/10 - 7 % 7 +(n * 7)+ a]

Try it online!

Takes the year, the month and the weekday as numbers, 1-indexed, Monday is the first day of the week.

\$\endgroup\$
4
  • \$\begingroup\$ huh, to-date is a thing. maybe this would be useful in the christmase eve format challenge \$\endgroup\$
    – ASCII-only
    Jan 2, 2019 at 9:18
  • \$\begingroup\$ @ASCII-only We used now for that challenge \$\endgroup\$ 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
    Jan 2, 2019 at 9:21
  • \$\begingroup\$ @ASCII-only >> 25-Dec-2019 - 1-1-2019 == 358 \$\endgroup\$ Jan 2, 2019 at 9:24
0
\$\begingroup\$

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.

\$\endgroup\$
5
  • \$\begingroup\$ Is the day of week in the format Sunday-Saturday or Monday-Sunday? \$\endgroup\$
    – Gymhgy
    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
    Jan 1, 2019 at 22:51
  • \$\begingroup\$ @EmbodimentofIgnorance, Sunday is 0 in JS. \$\endgroup\$
    – Shaggy
    Jan 1, 2019 at 22:52
  • \$\begingroup\$ Oh. I didn't know that, I'm not that familiar with Javascript. \$\endgroup\$
    – Gymhgy
    Jan 1, 2019 at 22:52
  • \$\begingroup\$ 48 bytes \$\endgroup\$
    – Shaggy
    Jan 2, 2019 at 10:51
0
\$\begingroup\$

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

Try it out

\$\endgroup\$
0
\$\begingroup\$

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}

Try it online!

\$\endgroup\$
3
  • 1
    \$\begingroup\$ 74 - uses same method as Scala and Groovy answers \$\endgroup\$
    – ASCII-only
    Jan 7, 2019 at 4:30
  • 1
    \$\begingroup\$ Fixed, 84 \$\endgroup\$
    – ASCII-only
    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
    Jan 10, 2019 at 9:31
0
\$\begingroup\$

APL (Dyalog Unicode), 36 28 bytesSBCS

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)

\$\endgroup\$
0
\$\begingroup\$

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")}

Attempt This Online!

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.