8
\$\begingroup\$

The day of the week and month of the year seem to get a lot of attention but no one seems to care about the week of the year. I believe it's time to change that, so your job is to write a program or function that when given a date outputs an integer between 1 and 53 corresponding to the current week of the year.

For the purposes of this challenge we will say that the first Sunday of the year marks the beginning of the year so the only case when January 1st is considered week 1 is when it falls on a Sunday.

  • Input can be any date format which does not explicitly include the week number (just specify the format in your answer) for dates between 1JAN1900 and 31DEC2100.
  • Output is an integer between 1 and 53
  • You may use any standard methods of providing input/output.

Test Cases

17MAY2017 -> 20

3JAN2013 -> 53

1JAN2017 -> 1

17MAY1901 -> 19

31DEC2100 -> 52

7JUL2015 -> 27
  • This is so all standard golfing rules apply, and the shortest code (in bytes) wins.
\$\endgroup\$
  • 4
    \$\begingroup\$ ISO weeks would be more standard; IIRC they're based on the first Thursday in a year. \$\endgroup\$ – Neil May 17 '17 at 15:53
  • \$\begingroup\$ Can we use other date input formats (i.e., 07/07/2015)? Can 7JUL2015 be 07JUL2015? \$\endgroup\$ – Stephen May 17 '17 at 16:14
  • \$\begingroup\$ @StephenS Yes, that's fine. 7/7/2015, 2015-07-07 are also valid. \$\endgroup\$ – J_Lard May 17 '17 at 16:16
  • 2
    \$\begingroup\$ @Neil: Not exactly matching the standard definition is a good thing here, it makes it less likely that the problem can just be solved via a builtin, whilst making it no more difficult to solve without. \$\endgroup\$ – user62131 May 17 '17 at 17:28
  • 4
    \$\begingroup\$ Note to people using %U: As @J_Lard points out, you need to take care as to whether week 0 is week 52 or 53 of the previous year. It's week 53 in 2001, 2007, 2013, 2018, 2024, 2029 and repeating in a 28-year cycle. Other years it's week 52. \$\endgroup\$ – Neil May 17 '17 at 19:41
2
\$\begingroup\$

Ohm, 12 33 bytes

EDIT: Fixed the edge cases for "%U".

IΩDÖ?┼╓y≤s"-12-31"C"%F"╓₧Ω
"%U"╓&

Assumes input can be a timestamp. Explanation to come.

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ Week 0 is different in years such as 1995 and 2023. \$\endgroup\$ – Neil May 17 '17 at 19:29
  • \$\begingroup\$ @Neil That's true, but the challenge says the answer must be in between 1 and 53, and I'm basically doing the same thing as all the other answers. \$\endgroup\$ – Nick Clifford May 17 '17 at 19:34
  • \$\begingroup\$ Sorry, I got my years mixed up. Anyway, it's 52 in some years, and 53 in others. \$\endgroup\$ – Neil May 17 '17 at 19:36
  • \$\begingroup\$ @Neil There we go. \$\endgroup\$ – Nick Clifford May 17 '17 at 20:31
  • 1
    \$\begingroup\$ Indeed, this gives correct answers for e.g. Jan 1 2018 and 2019. \$\endgroup\$ – Neil May 17 '17 at 20:55
6
\$\begingroup\$

MATL, 50 bytes

Thanks to @Neil and @NickClifford for pointing out a mistake, now corrected

ZO1)TThXJYOXIGYO&:8XO!s310=sJ4B-YOIq&:8XO!s310=sX\

Try it online! Or verify all test cases.

Explanation

This uses the three date/time conversion functions that there are in MATL:

  • XO: convert date and time to string format;
  • YO: convert date and time to serial date number;
  • ZO: convert date and time to vector of components.

Determining if week "0" should become 52 or 53 was costly, because MATL cannot define callable functions to reuse the 8XO!s310=s part. Reusing by means of loop with a branch only saves one byte, and complicates the explanation, so probably not worth it.

Also, something could be gained inputting the date as a [year, month, day] array; but the I would not use all three date functions :-)

Consider input '17MAY2017' as an example.

       % Implicit input
       % STACK: '17MAY2017'
ZO     % Convert to date vector
       % STACK: [2017 5 17]
1)     % Get first entry: year
       % STACK: 2017
TTh    % Append [1 1]
       % STACK: [2017 1 1]
XJ     % Copy to clipboard J
YO     % Convert to date number
       % STACK: 736696
XI     % Copy to clipboard I
GYO    % Push input again. Convert to date number
       % STACK: [736696 736832]
&:     % Binary range
       % STACK: [736696 736697 736698 ... 736832]
8XO    % Convert to date string with format 'ddd': day of week
       % STACK: ['Sun'; 'Mon'; 'Tue'; ... ; 'Wed']
!s     % Sum of each row (chars are interpreted as code points)
       % STACK: [310 298 302 ...  288]
310=   % Compare with 310 (sum of 'Sun')
       % STACK: [1 0 0 ... 0]
s      % Sum of array. If is 0, it needs to be transformed into 52 or 53,
       % depending on the number of Sundays the previous year contains.
       % STACK: 20
J      % Paste from clipboard J
       % STACK: 20, [2017 1 1]
4B-    % Push [1 0 0] and subtract element-wise
       % STACK: 20, [2016 1 1]
YO     % COnvert to date number
       % STACK: 20, 736330
I      % Paste from clipboard I
       % STACK: 20, 736330, 736696
q      % Subtract 1
       % STACK: 20, 736330, 736695
&:     % Binary range
       % STACK: 20, [736330 736331 736332 ... 736695]
8XO    % Convert to date string with format 'ddd': day of week
       % STACK: 20, ['Fri'; 'Sat'; 'Sun'; ... ; 'Sat']
!s     % Sum of each row (chars are interpreted as code points)
       % STACK: 20, [289 296 310 ... 296]
310=   % Compare with 310 (sum of 'Sun')
       % STACK: 20, [0 0 1 ... 0]
s      % Sum of array
       % STACK: 20, 52
X\     % 1-based modulo
       % STACK: 20
       % Implicit display
\$\endgroup\$
  • 2
    \$\begingroup\$ Congrats on 50k! I'm right there behind you :) \$\endgroup\$ – Digital Trauma May 17 '17 at 17:47
  • 1
    \$\begingroup\$ 2 points to go... and boom! Congrats! \$\endgroup\$ – Jonathan Allan May 17 '17 at 18:07
  • \$\begingroup\$ Does this work with the edge cases pointed out by Neil? I know it doesn't use %U, but I just want to make sure. \$\endgroup\$ – Nick Clifford May 17 '17 at 20:43
  • \$\begingroup\$ This seems to think 1st Jan 2019 is in Week 53, but it's only in Week 52. \$\endgroup\$ – Neil May 17 '17 at 20:58
  • \$\begingroup\$ @Neil Yes, you're correct. Interestingly the other test cases are correct. \$\endgroup\$ – J_Lard May 17 '17 at 21:03
4
\$\begingroup\$

JavaScript (ES6), 82 80 bytes

Takes input as (year,month,day).

let f =

(y,m,d)=>-~((((x=new Date(y,m-1,d))-new Date(y,0,1))/864e5+372-x.getDay())/7%53)

console.log(f(2017, 5,17)) // 20
console.log(f(2013, 1, 3)) // 53
console.log(f(2017, 1, 1)) // 1
console.log(f(1901, 5,17)) // 19
console.log(f(2100,12,31)) // 52
console.log(f(2015, 7, 7)) // 27

\$\endgroup\$
4
\$\begingroup\$

JavaScript (Firefox 34+), 70 bytes

with(new Date())y.value=getFullYear(),m.value=getMonth()+1,d.value=getDate()+1
f=
(y,m,d)=>new Date(y,--m,d-new Date(y,m,d).getDay()).toLocaleFormat`%U`
<div oninput=w.value=f(y.value,m.value,d.value)><input id=y type=number><input id=m type=number min=1 max=12><input id=d type=number min=1 max=31><input id=w readonly placeholder=Output>

Works by finding the first day of the week containing the given date, then finding that day's week number (which is never zero).

\$\endgroup\$
  • \$\begingroup\$ +1 for with. Always +1 for with! \$\endgroup\$ – Shaggy May 17 '17 at 21:13
2
\$\begingroup\$

Python 2, 70 64 bytes

Input => (year,month,day)

from datetime import*;lambda*v:int(date(*v).strftime('%U'))or 53

print(f(2017, 5,17)) #20
print(f(2013, 1, 3)) #53
print(f(2017, 1, 1)) #1
print(f(1901, 5,17)) #19
print(f(2100,12,31)) #52
print(f(2015, 7, 7)) #27

-6 bytes, thanks to @ovs

\$\endgroup\$
2
\$\begingroup\$

JavaScript (Firefox Only), 77 bytes

Takes date as string: i.e. Jan 1, 2017

s=>+new Date(s)[k='toLocaleFormat']`%U`||new Date(s.slice(-4)-1,11,31)[k]`%U`
\$\endgroup\$
  • \$\begingroup\$ Nice try but "week 0" isn't always the same week (1995 and 2023 are different). \$\endgroup\$ – Neil May 17 '17 at 19:28
  • \$\begingroup\$ Sorry, wrong test cases. I should post a proper comment on the question. \$\endgroup\$ – Neil May 17 '17 at 19:37
  • \$\begingroup\$ @Neil It should be corrected. \$\endgroup\$ – powelles May 17 '17 at 20:58
2
\$\begingroup\$

PHP, 125 Bytes

for($w=53,$a=0;($c=date_create)($argn)>=$n=date_modify($c("07JAN1900"),"+$a week");$a++)$w=date_format($n,z)<7?1:$w+1;echo$w;

Try it online!

PHP, 28 Bytes

Version for Monday instead Sunday

<?=date(W,strtotime($argn));

Try it online!

\$\endgroup\$
2
\$\begingroup\$

C#, 138 123 121 bytes

namespace System.Globalization{d=>CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(d,(CalendarWeekRule)1,(DayOfWeek)0);}

Turns out there's a built in for that, although it is rather large...

namespace System.Globalization
{
    Func<DateTime, int> f = d =>
        CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(d, (CalendarWeekRule)1, (DayOfWeek)0);
 }
\$\endgroup\$
1
\$\begingroup\$

Powershell, 260 + 8 = 268 bytes

+8 bytes because of the -DateTime flag


Accepts argument as "day month year" format.

function W([datetime]$DateTime = (Get-Date)) {
$cultureInfo = [System.Globalization.CultureInfo]::CurrentCulture
$cultureInfo.Calendar.GetWeekOfYear($DateTime,$cultureInfo.DateTimeFormat.CalendarWeekRule,$cultureInfo.DateTimeFormat.FirstDayOfWeek)
}

Not Powershell expert, can't golf


Test case

>W -DateTime "11 March 2015"
11
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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