Get the date of the nth day of week in a given year and month

17

3

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.

Embodiment of Ignorance

Posted 2019-01-01T20:28:42.200

Reputation: 7 014

1

I thought I might be able to use GNU date, but amusingly, the parser has an... interesting interpretation here.

– Doorknob – 2019-01-01T20:44:55.660

May week number be 0-indexed? – Jo King – 2019-01-02T01:52:14.380

Sure, if it suits your program – Embodiment of Ignorance – 2019-01-02T02:12:57.630

Suggested test case: 2018, 12, Sunday 1 – Adám – 2019-01-02T10:55:10.583

Suggested test case: the first Saturday in September 2019 – Shaggy – 2019-01-02T12:07:41.090

@Shaggy and Adam Added – Embodiment of Ignorance – 2019-01-02T16:28:56.463

Answers

4

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

tsh

Posted 2019-01-01T20:28:42.200

Reputation: 13 072

3

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()

Shaggy

Posted 2019-01-01T20:28:42.200

Reputation: 24 623

2

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

12Me21

Posted 2019-01-01T20:28:42.200

Reputation: 6 110

2

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.

dana

Posted 2019-01-01T20:28:42.200

Reputation: 2 541

If you only return the day of the month, which is allowed, you can golf this down to 59 bytes

– Embodiment of Ignorance – 2019-01-02T03:04:06.313

Thanks for the tip again - (that's 2x today ;) I will update my answers. – dana – 2019-01-02T04:14:30.667

2

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

Jo King

Posted 2019-01-01T20:28:42.200

Reputation: 38 234

I think the week number needs to be 1-indexed – 12Me21 – 2019-01-02T01:37:34.870

@12Me21 The question says that input is flexible, but I've asked whether we an take week number as 0 indexed – Jo King – 2019-01-02T01:55:12.037

This doesn't seem to work for other months. I think you need $^c+4-$!.daycount. – nwellnhof – 2019-01-02T02:24:08.063

@nwellnhof Ah, I should have thought of that instead of trial and error, lol. Should be fixed now – Jo King – 2019-01-02T03:00:14.820

1

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'

Luis Mendo

Posted 2019-01-01T20:28:42.200

Reputation: 87 464

1

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)

digEmAll

Posted 2019-01-01T20:28:42.200

Reputation: 4 599

1

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]

Neil A.

Posted 2019-01-01T20:28:42.200

Reputation: 2 038

0

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.

Кирилл Малышев

Posted 2019-01-01T20:28:42.200

Reputation: 439

131 bytes – Shaggy – 2019-01-01T23:42:04.257

Also, I don't think you need the of in the input. – Shaggy – 2019-01-01T23:58:17.247

@Shaggy, I think these are details. There may be many options. – Кирилл Малышев – 2019-01-02T00:00:41.430

0

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.

Neil

Posted 2019-01-01T20:28:42.200

Reputation: 95 035

Is the day of week in the format Sunday-Saturday or Monday-Sunday? – Embodiment of Ignorance – 2019-01-01T22:48:18.230

@EmbodimentofIgnorance Sorry, I knew I had forgotten something. (The snippet now uses select to make it easier.) – Neil – 2019-01-01T22:51:12.697

@EmbodimentofIgnorance, Sunday is 0 in JS. – Shaggy – 2019-01-01T22:52:03.957

Oh. I didn't know that, I'm not that familiar with Javascript. – Embodiment of Ignorance – 2019-01-01T22:52:36.697

48 bytes – Shaggy – 2019-01-02T10:51:03.437

0

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

ASCII-only

Posted 2019-01-01T20:28:42.200

Reputation: 4 687

0

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.

Galen Ivanov

Posted 2019-01-01T20:28:42.200

Reputation: 13 815

huh, to-date is a thing. maybe this would be useful in the christmase eve format challenge – ASCII-only – 2019-01-02T09:18:40.793

@ASCII-only We used now for that challenge – Galen Ivanov – 2019-01-02T09:21:30.280

1yeah, but i was thinking of alternative methods (namely, the <repeat " Eve" date2-date1 times> method iirc) – ASCII-only – 2019-01-02T09:21:48.300

@ASCII-only >> 25-Dec-2019 - 1-1-2019 == 358 – Galen Ivanov – 2019-01-02T09:24:01.317

0

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!

ASCII-only

Posted 2019-01-01T20:28:42.200

Reputation: 4 687

0

APL (Dyalog Unicode), 36 bytesSBCS

Full program. Prompts for [year,month] (January is 1), then for day (Sunday is 0), then for n (first is 1).

date⎕⊃d/⍨⎕=7|d←(⍳31)+days⎕⊣⎕CY'dfns'

Try it online!

⎕CY'dfns'copy in the dfns library

 discard the result of that in favour of…

 prompt console for [year,month] numbers

days[c] days[n] 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

date[c] datetime stamp[n] (has trailing zeros for hours, minutes, seconds, milliseconds)


Click [c] for code and [n] for notes.

Adám

Posted 2019-01-01T20:28:42.200

Reputation: 37 779

0

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

t-clausen.dk

Posted 2019-01-01T20:28:42.200

Reputation: 2 874

0

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!

JohnWells

Posted 2019-01-01T20:28:42.200

Reputation: 611

174 - uses same method as Scala and Groovy answers – ASCII-only – 2019-01-07T04:30:30.573

1Fixed, 84 – ASCII-only – 2019-01-07T04:35:46.850

1No need for the import command anymore so that's not a problem :P – ASCII-only – 2019-01-10T09:31:20.057