How many friday the 13th in a year?

28

3

Your challenge is to write a program which, given a year, outputs the number of "Friday 13ths" in it.

Rules & Details:

  • You can take input via STDIN, or as an argument passed to your program.
  • You should output the result to STDOUT.
  • You may assume that input will be a valid year, and does not pre-date the Gregorian calendar (undefined behaviour is permitted in these cases).
  • Calendar/Date libraries are allowed.

This is a , so the shortest code (in bytes) wins.

(Related challenge link)

Cruncher

Posted 2013-12-10T20:47:03.653

Reputation: 2 135

7What is the required range of input? If it goes much before 1800, what assumptions should be made about switchover from Julian to Gregorian calendar? – Peter Taylor – 2013-12-10T22:47:18.733

@PeterTaylor I hadn't thought about it. If a date pre-dates gregorian then you can have undefined behaviour. – Cruncher – 2013-12-11T14:05:55.620

1The first countries to adopt the Gregorian calendar did so in October 1582, following the bull of Gregory himself. Countries to adopt the new calendar late did not change until the 20th century, for example Greece introduced it on 1 March 1923. – Jeppe Stig Nielsen – 2013-12-11T14:16:05.420

@JeppeStigNielsen I don't know much about calendars and such. Whether they adopted them or not doesn't change what the gregorian dates are. Libraries should be able to calculate dates from quite a ways back I presume? – Cruncher – 2013-12-11T14:17:24.620

3I am being offtopic here, I guess. Many libraries written by Anglo-American programmers use September 1752 as the "correct" time of change of calendars. This was when the British Empire changed. The new calendar was kept when U.S.A. was founded, of course. (As a curiosity, some SQL software has 1753 as the minimal year since they don't want to cope with the September 1752 issue.) However, using September 1752 is highly anglocentric. You are right Gregorian dates are the same whether they were used historically or not. That is the so-called proleptic Gregorian calendar. – Jeppe Stig Nielsen – 2013-12-11T14:38:55.423

Answers

3

APL (Dyalog APL) with cal from dfns, 29 bytes

+/{13∊⍎,⍉3↑¯5↑⍉2↓cal⍵}¨⎕,¨⍳12

Try it online!

⍳ 12 the integers one through twelve

⎕ ,¨ take numeric input and prepend to each of the twelve numbers

{ on each of the pairs, apply the function…

cal⍵ get a calendar for that year-month

2 ↓ drop two rows (caption and days)

 transpose (so we can address columns instead of rows)

¯5 ↑ take the last five (two digits for each of Friday and Saturday plus one space)

3 ↑ take the first two (two digits for Friday plus a space)

 transpose (so we get reading order)

, ravel

 execute as APL expression (gives list of Fridays' dates)

13 ∊ is thirteen a member of that list?

+/ sum the 12 Booleans


Using @Wrzlprmft's algorithm, we can do it without libraries for 53 bytes:

'21232211321211'⊃⍨14|2 3 ¯1+.×⊢,0≠.=400 100 4∘.|-∘0 1

-∘0 1 subtract zero and one

400 100 4 ∘.| division remainder table for the two years (across) divided by these numbers (down)

0 ≠.= inner "product" with 0, but using ≠ and = instead of +.×

⊢ , prepend the unmodified argument year

2 3 ¯1 +.× inner product with these numbers

14 | division remainder when divided by fourteen

'21232211321211' ⌷⍨ index into this string

Adám

Posted 2013-12-10T20:47:03.653

Reputation: 37 779

It's 29 characters, but these are more than 1 byte characters right? – Cruncher – 2017-03-01T12:18:42.150

@Cruncher I've added an explanatory link in the heading. If you open the TIO link, you'll see that it says "29 chars, 29 bytes (SBCS)" on the right, i.e. Single Byte Character Set. – Adám – 2017-03-01T12:21:59.193

Well, I guess this is the new winner then, is standard practice in this SE to change the accepted answer this long after the question? – Cruncher – 2017-03-01T12:28:56.843

@Cruncher Yes. And there are even badges to be had for getting accepted long after OP. – Adám – 2017-03-01T12:31:14.393

12

Mathematica 49 46 45 44 42

As a pure function: 42 chars

DayName@{#,m,6}~Table~{m,12}~Count~Friday&

Example

DayName@{#,m,6}~Table~{m,12}~Count~Friday&[2013]

2


As a named function: 44 chars

f=DayName@{#,m,6}~Table~{m,12}~Count~Friday&

Examples

f[1776]
f[2012]
f[2013]
f[2014]

2
3
2
1

DavidC

Posted 2013-12-10T20:47:03.653

Reputation: 24 524

One character shorter: f=DayName@{#,m,6}~Table~{m,12}~Count~Friday& – Mr.Wizard – 2013-12-11T10:25:05.240

@Mr.Wizard Yes. It surprises me that Mathematica can parse the multiple cases of infix notation. – DavidC – 2013-12-11T13:26:05.290

David it surprises me that you haven't seen my (over)use of this conjoined notation. :^) (Examples: (1), (2))

– Mr.Wizard – 2013-12-11T18:42:27.500

8

Ruby, 49 48 47 46

f=->m{(1..12).count{|i|Time.gm(m,i,6).friday?}}

Edit: Shaved a character by going back a week, thanks to Jan, and another by switching from Time.new to Time.gm

Edit: At the expense of obfuscating it a bit more, I can get to 46 with

f=->m{(1..12).count{|i|Time.gm(m,i,8).wday<1}}

histocrat

Posted 2013-12-10T20:47:03.653

Reputation: 20 600

If the 8th is a Sunday, then the 1st is as well, and so you can use Time.gm(m,i).wday<1. Also, I don't know why you're naming the function. – Lee W – 2016-12-14T19:08:03.233

You can remove f= if the rest is a complete function expression (in this case a lambda) – Cyoce – 2017-03-01T17:33:42.213

5one-char saving if you count the numbers of fridays the 6th – John Dvorak – 2013-12-10T21:53:52.870

2@JanDvorak clever! – histocrat – 2013-12-10T22:11:40.400

why 6? I didn't get it. – NARKOZ – 2013-12-11T08:28:23.250

3If the 6th is a friday, then the 13th is also a friday – TwiNight – 2013-12-11T09:26:27.583

8

Powershell, 68 63 58 52 50

Thanks Iszi for the tip.

$n=$args;(1..12|?{!+(date $n-$_).DayOfWeek}).Count

Using the fact that if the 1st day in the month is Sunday, the 13th will be Friday.

I've also tried:

(1..12|?{!+(date $args-$_).DayOfWeek}).Count

but it's not the same $args inside the script block.

Danko Durbić

Posted 2013-12-10T20:47:03.653

Reputation: 10 241

1I like the idea of using the first day of the month. – Cruncher – 2013-12-10T21:54:36.670

Nice trick, there. The @ is unnecessary, though. – Iszi – 2013-12-10T23:51:15.377

Another thing, though I'm guilty of the same in a lot of my scripts. The challenge does specify that the input can come from an argument. Replace $n with $args in the loop, and you can do without $n=read-host; entirely. Saves 8. Remove @, as mentioned above, and you're down to 54. – Iszi – 2013-12-11T00:08:27.773

Correction: Comes down to 52! – Iszi – 2013-12-11T00:18:15.940

Trying to figure out why your second script won't work and I'm at a loss. What's interesting is that I can change out $args for $input, thus feeding the year in from the pipeline, and the script will run but it always outputs 3. – Iszi – 2013-12-12T01:27:44.587

I guess, in that case, $input enumerates the object that is currently in the pipeline, i.e. $input is the same as $_, so the script always operates on January year 1, February year 2, March year 3, and so on... – Danko Durbić – 2013-12-12T07:54:22.850

Nice. You can save 6 bytes $n=$args;(1..12|?{!(date $n-$_|% d*k)}).Count – mazzy – 2018-09-27T08:11:50.407

5

R 76 72 57

sum(format(as.Date(paste(scan(),1:12,1,sep="-")),"%w")<1)

flodel

Posted 2013-12-10T20:47:03.653

Reputation: 2 345

Can easily get this down 4 by replacing your "%a %d")=="Fri 13" with "%w%d)=="513") by using dow as a number, and removing the spaces. – chmullig – 2013-12-11T03:01:20.547

much appreciated! – flodel – 2013-12-11T03:11:39.440

+1 Though doing the seq only on the month is actually shorter here! sum(format(as.Date(paste(scan(),1:12,13,sep="-")),"%w%d")=="513")is only 65 characters! – plannapus – 2013-12-11T08:36:59.737

wow I wouldn't have guessed that < would coerce a character to an integer. Nice trick! – plannapus – 2013-12-11T13:35:10.060

@plannapus It's rather common. Since character codes are all numbers. Even java can compare int and char – Cruncher – 2013-12-11T14:38:35.577

It is the other way around. The integer is coerced to a character. See for example that "0.2e2" < 1 is TRUE. – flodel – 2013-12-11T15:07:23.800

I really have a short memory cause this is the exact same thing as the "TRUE"==TRUE issue. – plannapus – 2013-12-11T15:18:26.433

5

Python2.7 90 86

from datetime import*
s=c=0
exec's+=1;c+=date(%d,s,9).weekday()<1;'%input()*12
print c

Monday the 9th may not have quite the same ring to it but works just as well.

Edit: A year and a half to notice that date is shorter than datetime :)

ejrb

Posted 2013-12-10T20:47:03.653

Reputation: 256

Nice! I ended up with something effectively identical, but avoiding exec: f=lambda y:sum([date(y,m,13).weekday()==4 for m in range(1,13)]).... Same size solution with the import (86 bytes), though. – iwaseatenbyagrue – 2017-03-01T15:03:50.300

Really nice solution! – leancz – 2013-12-11T16:20:09.090

2You can save a char by doing from datetime import* – user80551 – 2014-04-08T15:49:20.710

5

Not using any libraries or built-in date functions:

Golfscript – 51

~..({4/.25/.4/--@}2*2*\3*+-
14%' [3/=RI[)a%:*.'\=5%

' [3/=RI[)a%:*.' could as well be 'feefefgeeffgfe'

Python – 82 79

Essentially the same algorithm.

l=lambda y:y/4-y/100+y/400
i=input()
print"21232211321211"[(2*i+3*l(i)-l(i-1))%14]

Using this trick, this can be golfed down further to:

l=lambda y:y/4-y/100+y/400
i=input()
print 94067430>>(4*i+6*l(i)-2*l(i-1))%28&3

This exploits the fact that, calender-wise, there are only 14 different years, which are distinguishable by their last day and whether they are leaping. l calculates the number of leap years up to its argument (if the Gregorian calendar extended backwards to the year 1). (2*i+3*l(i)-l(i-1))%14 is short for l(i)-l(i-1)+(i+l(i))%7*2, where l(i)-l(i-1) tells us whether the argument is a leap year and i+l(i) sums up the shifts of the last day (one in a normal year, two in a leap year).

Wrzlprmft

Posted 2013-12-10T20:47:03.653

Reputation: 2 772

Since this is my first golfscript golf, I would appreciate any hints on further golfing it down. – Wrzlprmft – 2014-04-10T14:27:19.190

I was thinking about such a solution utilizing the fact that there's only 14 unique years actually, but wasn't sure the best language to make it competetive. I think this is the shortest answer with no libraries. If leap years were uniformly every 4 years, you might be able to win with this – Cruncher – 2014-04-10T15:36:52.710

4

C 301+ 287

main(int x,char**v){char p[400],*a[]={"abbababbacaacbac","bacabbb","baabbaca","abbb","aabbacaac","abbbbcaac","abbbbaabb"},*b="adcadcadcaebcadcadcafbcadcadcagbcadcadcadc";int c=0,i,y=atoi(v[0]);for(i=0;i<42;i++)strcpy(&p[c],a[b[i]-'a']),c+=strlen(a[b[i]-'a']);printf("%d",p[y%400]-'`');}

Not the shortest answer, but uses no libraries.

Williham Totland

Posted 2013-12-10T20:47:03.653

Reputation: 1 186

Hey, would you be willing to provide the ungolfed answer with an explanation? I'm interested in what exactly you did – Cruncher – 2013-12-11T14:07:59.600

1@Cruncher, it's a lookup table on the basis that the Gregorian calendar follows a 400-year cycle. – Peter Taylor – 2013-12-11T14:20:03.907

1More explicitly (and longer), C#: static char GetNumberOfFriday13s(int year) { const string perpetualCalendar = "1221212213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213112213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122213113213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122221122213122221122131122121221311321312222112213112212122131132131222211221311221212213113213122221122131"; return perpetualCalendar[year % 400];. Won't work for negative years. – Jeppe Stig Nielsen – 2013-12-11T15:01:28.773

Cute! As a small bug, v[0] should be v[1]. You can also golf this a bit; consider using strcat, storing characters to directly print in a[], and subtracting numeric constants instead of character constants. :) – user1354557 – 2013-12-11T17:23:04.973

main(int x,char**v){char p[400],*a[]={"1221212213113213","2131222","21122131","1222","112213113","122223113","122221122"},*b="adcadcadcaebcadcadcafbcadcadcagbcadcadcadc";*p=0;for(;*b;b++)strcat(p,a[*b-97]);putchar(p[atoi(v[1])%400]);} (234 chars) – user1354557 – 2013-12-11T17:44:46.093

1I improved the compression as well: main(int x,char**v){char p[400],*a[]={"1221212213113213","2131222","21122131","1222","112213113","122223113","122221122"},*b="adcadcadcaebcadcadcafbcadcadcagbcadcadcadc";*p=0;for(;*b;b++)strcat(p,a[*b-97]);putchar(p[atoi(v[1])%400]);} (215 chars) – user1354557 – 2013-12-11T18:55:56.200

4

JavaScript, 70

f=function(a){b=0;for(c=12;c--;)b+=!new Date(a,c,1).getDay();return b}

guy777

Posted 2013-12-10T20:47:03.653

Reputation: 153

and why it is -1? – Lukasz 'Severiaan' Grela – 2013-12-11T11:03:41.763

1Looks good! You can save a few more bytes, by removing ,b,c from the function declaration (it's ok to leak vars for golf!), also as b is cast as a Number you can += the result of test instead of the &&b++: b+=/^F/.test(new Date(a,c,6)). However, you can save another byte, using !new Date(a,c,1).getDay() (this works because getDay returns 0 for Sunday, and if the 13th is a Friday, the 1st will be a Sunday) instead of the test which altogether should save you 7 bytes! – Dom Hastings – 2013-12-11T17:11:29.770

@DomHastings : thx for your tips !!! – guy777 – 2013-12-11T21:27:39.107

4

bash 47 36

seq -f$1-%g-6 12|date -f-|grep -c ^F

Thanks @DigitalTrauma for saving 10 chars by using seq with default start to 1.

date -f<(printf "%s\n" $1-{1..12}-6)|grep -c ^F

(Previous version using echo present a bug because of the empty line when <(echo $1-{1..12}-6$'\n'). So this function worked fine until today is a Friday.

Lets see:

set -- 2013
seq -f$1-%g-6 1 12|date -f-|grep -c ^F
2

date -f<(printf "%s\n" $1-{1..12}-13)|grep -c ^F
2

Is is locale dependant, si if it don't work, you may have to

export LANG=C

or

LANG=C date -f<(printf "%s\n" $1-{1..12}-13)|grep -c ^F

Into a function; +7 -> 43

f(){ seq -f$1-%g-6 12|date -f-|grep -c ^F;}

f 2013
2

for i in {2010..2017};do echo $i $(f $i) ;done
2010 1
2011 1
2012 3
2013 2
2014 1
2015 3
2016 1
2017 2

Bonus: +78 -> 121

From there, if my function become:

f(){ o=();for t in $(seq -f$1-%g-6 12|date -f- +%a,%b);do [ "${t:0:1}" = "F" ]&&o+=(${t#*,});done;echo ${#o[@]} ${o[@]};}

or

f(){ o=();
     for t in $(seq -f$1-%g-6 1 12|date -f- +%a,%b);do
         [ "${t:0:1}" = "F" ]&&o+=(${t#*,})
       done
     echo ${#o[@]} ${o[@]}
}

for i in {2010..2017};do echo $i $(f $i) ;done
2010 1 Aug
2011 1 May
2012 3 Jan Apr Jul
2013 2 Sep Dec
2014 1 Jun
2015 3 Feb Mar Nov
2016 1 May
2017 2 Jan Oct

F. Hauri

Posted 2013-12-10T20:47:03.653

Reputation: 2 654

This seems to be locale-dependent. – Peter Taylor – 2013-12-11T14:17:46.053

Yes, This is based on default C. But there is a bug... – F. Hauri – 2013-12-11T14:36:37.677

Save a char by unquoting your printf format string and escaping the \ instead: %s\\n – Digital Trauma – 2014-04-08T21:37:06.883

1Or use seq to drop 8 chars: date -f<(seq -f$1-%g-6 1 12)|grep -c ^F – Digital Trauma – 2014-04-08T21:40:15.993

@DigitalTrauma Thanks! Post edited! – F. Hauri – 2014-04-08T23:29:42.340

@DigitalTrauma I have to win this, if my count is right!? – F. Hauri – 2014-04-08T23:33:10.373

@F.Hauri There's this one http://codegolf.stackexchange.com/a/25525/11259 which is neck-and-neck with you if corrected according to my comment

– Digital Trauma – 2014-04-08T23:49:07.077

1Actually, you can shave off 2 more chars. If you omit the starting sequence number, seq will start at 1 by default, which it what you want: seq -f$1-%g-6 12|date -f-|grep -c ^F – Digital Trauma – 2014-04-09T16:36:27.443

4

C (151 145 137 131 130 chars)

I am surprised to see that there is only one other solution that doesn't use built-in calendar tools. Here is a (highly obfuscated) mathematical approach, also in C:

f(x){return(x+(x+3)/4-(x+99)/100+!!x)%7;}main(int x,char**v){int y=atoi(v[1])%400,a=f(y+1);putchar('1'+((f(y)&3)==1)+(a>2&&a-5));}

(The above compiles in GCC with no errors)

Alternative solution: C (287->215 chars)

I rather enjoyed Williham Totland's solution and his use of compression. I fixed two small bugs and tweaked the code to shorten its length:

main(int x,char**v){char p[400],*a[]={"1221212213113","213122221122131","12213113","22213113","22221122","2131"},*b="abababafcbababafdbababafebababab";*p=0;for(;*b;b++)strcat(p,a[*b-97]);putchar(p[atoi(v[1])%400]);}

user1354557

Posted 2013-12-10T20:47:03.653

Reputation: 251

4

PHP, 82

<?for($i=1,$c=0;$i<13;$i++)$c+=(date("N",mktime(0,0,0,$i,1,$argv[1]))==7);echo $c;

Based on

"Any month that starts on a Sunday contains a Friday the 13th, and there is at least one Friday the 13th in every calendar year."

From http://en.wikipedia.org/wiki/Friday_the_13th

dkasipovic

Posted 2013-12-10T20:47:03.653

Reputation: 229

3

k

64 characters

{+/6={x-7*x div 7}(.:')x,/:(".",'"0"^-2$'$:1+!:12),\:".13"}[0:0]

Reads from stdin

skeevey

Posted 2013-12-10T20:47:03.653

Reputation: 4 139

Ok, just what is going on here? :P – Williham Totland – 2013-12-11T11:31:38.400

Read in year, build list of dates of 13th day of every month, test day of week = friday, sum resulting list of booleans – skeevey – 2013-12-11T13:25:51.357

3

Common Lisp (CLISP), 149

(print 
    (loop for i from 1 to 12 count 
        (= 4 (nth-value 6 
            (decode-universal-time
                (encode-universal-time 0 0 0 13 i
                    (parse-integer (car *args*)) 0))))))

Pål GD

Posted 2013-12-10T20:47:03.653

Reputation: 383

Oh god, I never could read lisp.. – Cruncher – 2013-12-11T14:09:22.310

2

PHP, 55 bytes

for(;++$i<13;)$c+=!date(w,strtotime($argn.-$i));echo$c;

Run with echo <year> | php -nR '<code>'.

Basically the same that Oleg tried and Damir Kasipovic did, just with better golfing:
Every month that starts with a sunday, has a Friday the 13th.
So I loop through the months and count the first days that are sundays.

breakdown

for(;++$i<13;)          // loop $i from 1 to 12
    $c+=!                   // 4. if result is not truthy (weekday==0), increment $c
        date(w,             // 3. get weekday (0 stands for Sunday)
            strtotime(      // 2. convert to timestamp (midnight 1st day of the month)
                $argn.-$i   // 1. concatenate year, "-" and month
            )
        )
    ;
echo$c;                 // output

Titus

Posted 2013-12-10T20:47:03.653

Reputation: 13 814

2

C# 110 101 93 92

int f(int y){int c=0;for(int i=1;i<13;i++)c+=new DateTime(y,i,8).DayOfWeek>0?0:1;return c;}

C# Linq 88

int g(int y){return Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0);}

Thanks to Jeppe Stig Nielsen for linq and suggestion of checking for sunday on the 8th.

Thanks to Danko Durbić for suggesting > instead of ==.

Kami

Posted 2013-12-10T20:47:03.653

Reputation: 121

Instead of c+=(int)new DateTime(y,i,13).DayOfWeek==5?1:0;, use the equivalent c+=new DateTime(y,i,8).DayOfWeek==0?1:0;. The trick is to subtract 5, because then you can get rid of the cast to int, and also the number 8 has one digit less than the number 13. Sunday the Eighth! – Jeppe Stig Nielsen – 2013-12-11T12:48:20.890

With Linq: int g(int y){return Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0);}. Of course as a lambda this is y=>Enumerable.Range(1,12).Count(m=>new DateTime(y,m,8).DayOfWeek==0). – Jeppe Stig Nielsen – 2013-12-11T12:55:24.533

You can save one character by comparing .DayOfWeek<1. – Danko Durbić – 2013-12-11T22:04:29.597

@DankoDurbić This can apply to the c# answer but not sure how to apply it to linq . – Kami – 2013-12-12T11:02:49.560

My mistake; apparently you can't compare DayOfWeek with any other integer than 0 - error CS0019: Operator '<' cannot be applied to operands of type 'System.DayOfWeek' and 'int'. – Danko Durbić – 2013-12-12T12:38:07.630

1

Perl 6, 55 53

{sum (1..12).map: {Date.new($_,$^a,1).day-of-week>6}}

Old answer:

{sum (1..12).map: {Date.new($_,$^a,13).day-of-week==5}}

bb94

Posted 2013-12-10T20:47:03.653

Reputation: 1 831

48 bytes – Jo King – 2019-02-13T00:12:05.320

1

Python 195 / 204

Works only for previous years, because monthdatescalendar returns a calendar for the given year until now. I think there is a lot of optimizing potential left :).

import calendar, sys
c=calendar.Calendar()
f=0
for m in range(1,12):
 for w in c.monthdatescalendar(int(sys.argv[1]),m):
  for d in w:
   if d.weekday() == 4 and d.day == 13:
    f=f+1
print(f)

Another solution, works for every date but it isn't smaller:

import datetime,sys
y=int(sys.argv[1])
n=datetime.date
f=n(y,1,1)
l=n(y,12,31)
i=0
for o in range(f.toordinal(), l.toordinal()):
 d=f.fromordinal(o)
 if d.day == 13 and d.weekday() == 4:
  i=i+1
print(i)

klingt.net

Posted 2013-12-10T20:47:03.653

Reputation: 876

1You didn't even bother golfing. Remove some of those spaces. – mbomb007 – 2015-04-29T15:20:46.547

In your first example the range should be (1,13) otherwise you'd miss December Friday 13ths, like in 2013. – leancz – 2013-12-11T11:50:58.670

1

Bash (52 47 characters)

for m in {1..12};do cal $m $Y;done|grep -c ^15

jerous

Posted 2013-12-10T20:47:03.653

Reputation: 11

1

K, 42

{+/1={x-7*x div 7}"D"$"."/:'$+(x;1+!12;1)}

.

k){+/1={x-7*x div 7}"D"$"."/:'$+(x;1+!12;1)}'1776 2012 2013 2014
2 3 2 1

tmartin

Posted 2013-12-10T20:47:03.653

Reputation: 3 917

1

Rebol, 63

f: 0 repeat m 12[d: do ajoin["6-"m"-"y]if d/weekday = 5[++ f]]f

Usage example in Rebol console:

>> y: 2012
== 2012

>> f: 0 repeat m 12[d: do ajoin["6-"m"-"y]if d/weekday = 5[++ f]]f
== 3

Alternative solution which collects all the Friday 13th in given year is:

>> collect[repeat m 12[d: do ajoin["13-"m"-"y]if d/weekday = 5[keep d]]]
== [13-Jan-2012 13-Apr-2012 13-Jul-2012]

draegtun

Posted 2013-12-10T20:47:03.653

Reputation: 1 592

1

Bash and Sed, 39

ncal $1|sed '/F/s/13/\
/g'|grep -c ^\ 2

ncal prints a calendar for the given year with days of the week down the left.

sed with a /g flag subs out all 13s with newlines

grep -c counts the lines that start with " 2" (20 always follows 13)

Thanks to @DigitalTrauma for finding a bug in my old version and proposing a solution!

Not that Charles

Posted 2013-12-10T20:47:03.653

Reputation: 1 905

Doesn't quite work for me - Friday lines are only printed once even if they contain more than one 13. – Digital Trauma – 2014-04-08T22:16:18.567

1I think the best I can do with something like this is 38: ncal $1|sed /F/s/13/\\n/g|grep -c ^\ 2 – Digital Trauma – 2014-04-08T22:17:37.700

1@DigitalTrauma You're right. At some point this script was working. let me fix it. – Not that Charles – 2014-04-09T14:07:58.490

1@DigitalTrauma looks like some much longer version was working. thanks for the fix! – Not that Charles – 2014-04-09T15:44:30.420

Interesting, the unquoted sed expression I proposed works with GNU sed (Linux) but not with BSD sed (OSX). I guess you can gain 1 char at the cost of portability if you choose the GNU version. – Digital Trauma – 2014-04-09T16:26:58.150

1

Scala, 76 68 characters

In 78 chars:

def f(y:Int)=0 to 11 count(new java.util.GregorianCalendar(y,_,6).get(7)==6)

Nothing out of ordinary, except for using magical numbers for DAY_OF_WEEK = 7 and FRIDAY = 6.

68 character version:

def f(y:Int)=0 to 11 count(new java.util.Date(y-1900,_,6).getDay==5)

Yes, Java changed values of day of the week constants between API's.

Karol S

Posted 2013-12-10T20:47:03.653

Reputation: 161

It's a shame new java.util.GregorianCalendar has to be so long :( – Cruncher – 2014-04-10T15:32:40.820

0

Clojure, 207 187 bytes

-20 bytes by getting rid of the import, and some whitespace I missed.

(import '[java.time LocalDate DayOfWeek])#(loop[d(LocalDate/parse(str %"-01-01"))c 0](if(=(.getYear d)%)(recur(.plusDays d 1)(if(and(=(.getDayOfMonth d)13)(= (.getDayOfWeek d) DayOfWeek/FRIDAY))(inc c)c))c))

Starting on Janauary 1st of the given year, it loops over each day. If the day is Friday the 13th, it increments the count. It continues to loop until it reaches the next year.

(import '[java.time LocalDate DayOfWeek])

(defn count-friday-13ths [year]
  (loop [d (LocalDate/parse (str year "-01-01")) ; Starting date
         c 0] ; The count
    (if (= (.getYear d) year) ; If we haven't moved onto the next year...
      (recur (.plusDays d 1) ; Add a day...
             (if (and (= (.getDayOfMonth d) 13) ; And increment the count if it's Friday the 13th
                      (= (.getDayOfWeek d) DayOfWeek/FRIDAY))
               (inc c) c))
      c))) ; Return the count once we've started the next year.

Carcigenicate

Posted 2013-12-10T20:47:03.653

Reputation: 3 295

0

PHP, no builtins, 81 bytes

echo 0x5da5aa76d7699a>>(($y=$argn%400)+($y>102?$y>198?$y>299?48:32:16:0))%28*2&3;

Run with echo <year> | php -nR '<code>'.

breakdown

Weekdays repeat every 400 years.
In the results for 1600 to 1999 (for example), there is a 28-length period with just three gaps:

  0:2212122131132131222211221311
 28:2212122131132131222211221311
 56:2212122131132131222211221311
 84:2212122131132131122
103:       131132131222211221311
124:2212122131132131222211221311
152:2212122131132131222211221311
180:2212122131132131222
199:       131132131222211221311
220:2212122131132131222211221311
248:2212122131132131222211221311
276:221212213113213122221122
300:            2131222211221311
316:2212122131132131222211221311
344:2212122131132131222211221311
372:2212122131132131222211221311

After adjusting the year for these gaps, we can get the result with a simple hash:

$y=$argn%400;foreach([300,199,103]as$k)$y<$k?:$y+=16;
echo"2212122131132131222211221311"[$y%28];

Not short (95 bytes) but pretty. And we can golf

  • 4 bytes by using a ternary chain for the offset,
  • 8 bytes by converting the hash map from a base4 string to integer,
  • one more by using the hex representation,
  • and one by merging the expressions.

Titus

Posted 2013-12-10T20:47:03.653

Reputation: 13 814

A port of CompuChip´s C++ answer can be golfed down to 84 bytes: for(;++$m<13;23*$m/9+($m<3?$y--:$y-2)+5+$y/4-$y/100+$y/400)%7?:$f++)$y=$argn;echo$f;

– Titus – 2017-03-01T18:54:06.650

0

Python(v2) 120

import datetime as d,sys
s=0
for m in range(1, 13):
    if d.datetime(int(sys.argv[1]),m,6).weekday()==4: s=s+1
print s

leancz

Posted 2013-12-10T20:47:03.653

Reputation: 121

0

Perl + lib POSIX 55

With the idea of not looking for 13th but first, and as sunday is 0 this let save 3 chars! Thanks @ Iszi and Danko Durbić!

$==$_;$_=grep{!strftime"%w",0,0,0,1,$_,$=-1900}(0..11)

Could compute 2010 to 2017 (for sample) in this way:

perl -MPOSIX -pE '$==$_;$_=grep{!strftime"%w",0,0,0,1,$_,$=-1900}(0..11)' <(
    printf "%s\n" {2010..2017})
11321312

(Ok, there is no newline, but that was not asked;)

Old post: 63

$==grep{5==strftime"%w",0,0,0,13,$_,$ARGV[0]-1900}(0..11);say$=

In action:

for i in {2010..2017};do
    echo $i $(
        perl -MPOSIX -E '
            $==grep{5==strftime"%w",0,0,0,13,$_,$ARGV[0]-1900}(0..11);say$=
            ' $i );
  done
2010 1
2011 1
2012 3
2013 2
2014 1
2015 3
2016 1
2017 2

F. Hauri

Posted 2013-12-10T20:47:03.653

Reputation: 2 654

0

In Smalltalk (Squeak/Pharo flavour), implement this method in Integer (86 chars)

countFriday13^(1to:12)count:[:m|(Date year:self month:m day:13)dayOfWeekName='Friday']

Then use it like this: 2014countFriday13.

Of course, we could use a shorter name, but then it would not be Smalltalk

aka.nice

Posted 2013-12-10T20:47:03.653

Reputation: 411

0

Japt -x, 10 bytes

CÆ5¥ÐUXD e

Try it

CÆ5¥ÐUXD e     :Implicit input of integer U
C              :12
 Æ             :  Map each X in the range [0,C) (months are 0-indexed in JavaScript)
  5¥           :  Check if 5 is equal to
    ÐUXD       :  new Date(U,X,13)
         e     :  0-based index of day of the week
               :Implicitly reduce by addition and output

Shaggy

Posted 2013-12-10T20:47:03.653

Reputation: 24 623

0

JavaScript, 56 bytes

y=>(g=m=>m?g(--m)-(new Date(y,m,13).getDay()!=5):12)(12)

Try It Online!

Shaggy

Posted 2013-12-10T20:47:03.653

Reputation: 24 623

0

C++ - Too many bytes :(

I tried a solution which doesn't make use of any date libraries.

I found a pretty cool (if I may say so myself) solution. Unfortunately I can't get it shorter than this, which really bugs me because it feels like there should be a better way.

The solution hinges on this algorithm which is only 44 bytes in itself. Unfortunately I need another 100 bytes to wrap it nicely...

#include<stdlib.h>
main(int,char**v){int f=0,d,m,y;for(m=1;m<13;++m)d=13,y=atoi(v[1]),(d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7-5||++f;return f;}

Output through the return code (in C++, using cout or printf or anything like that requires another #include, which would blow up the solution even more).

Driver / test program:

# Make sure we're not running an old version
rm doomsday.exe

gcc doomsday.cpp -o doomsday.exe

./doomsday.exe 1776
echo 1766: $?

./doomsday.exe 2012
echo 2013: $?

./doomsday.exe 2013
echo 2013: $?

./doomsday.exe 2014
echo 2014: $?

echo `wc doomsday.cpp -c` characters

Output of the driver program:

$ ./test_doomsday 
1766: 2
2013: 3
2013: 2
2014: 1
150 doomsday.cpp characters

CompuChip

Posted 2013-12-10T20:47:03.653

Reputation: 439

I count 88 for the algorithm, not 44. What is the algorithm and what is the warpping? ($m<3?$y--:$y-2)+3 instead of d=13,, d+=m<3?y--:y-2, and d+4 should work as well and saves a lot. +5 instead of +3 and -5 should work too and saves 2 bytes. for(m=0;++m<13;) saves one byte. Moving m=0 to the function head saves another byte; and moving ()%7||++f to the loop head saves another one. Down from 149 to 136 bytes. – Titus – 2017-03-01T18:46:54.027

-2

VB.net

Not a CodeGolf attempt

Iterator Function SpecificDayOfTheWeekInYear(Year As Integer, DayOfTheWeek As DayOfWeek ) As IEnumerable(of Date)
  Dim FirstDayOfTheYear = New Date(Year,1,1)
  Dim CurrentDay = FirstDayOfTheYear.AddDays( DayOfTheWeek - FirstDayOfTheYear.DayOfWeek )
  If CurrentDay.Year < Year Then CurrentDay = CurrentDay.AddDays(7)
  While CurrentDay.Year = Year
    Yield CurrentDay 
    CurrentDay=CurrentDay.AddDays(7)
  End While
End Function

Which makes looking for Friday the 13th's simple.

Dim FridayThe13ths =  From d in SpecificDayOfTheWeekInYear(2013,DayOfWeek.Friday )
                     Where d.Day=13

or a much simpler

Iterator Function YieldDayInMonth(Year As Integer, Day As Integer) As IEnumerable(of date)
  For M=1 To 12
   Yield New Date(Year,M,Day )
  Next
End Function

This makes the coding thus.

Dim f13 = YieldDayInMonth( 2013, 13).Where( Function(d) d.DayOfWeek = DayOfWeek.Friday)

Adam Speight

Posted 2013-12-10T20:47:03.653

Reputation: 1 234

Why are you posting "Not a CodeGolf attempt" on a code golf? That seems a bit off topic and pointless. – Tim Seguine – 2014-04-10T18:55:50.353

@TimSeguine Bit like posting any vb.net entry is pointless, not like vb.net is ever going to "win" one of these is it? – Adam Speight – 2014-04-10T20:08:12.507

2It's more about cleverness than winning. If people like your entry, then you are likely to get upvotes even if you don't win. Choosing not to golf on a code golf question seems like not even trying. – Tim Seguine – 2014-04-10T20:11:20.980

Relevant meta post: http://meta.codegolf.stackexchange.com/a/1456/11909 I am not the only one who downvotes when things don't follow the spec.

– Tim Seguine – 2014-04-18T15:56:25.830