# Next Friday the 13th

What is the shortest program that can predict the next time Friday will fall on the 13th day of the month?

• Must be an complete functioning program (not just a function/subroutine)
• Must print out date in the following format: YYYY-MM-DD
• Allow user to provide a start date either as a command line argument or through STDIN
• If user provides no start date, use today as the start date.
• If the start date is a Friday the 13th, the program should find the next Friday the 13th.

If I were to run the program today (Feb 16 2011) I should get the following output.

$./fr13th 2013-05-09 2013-09-13$ ./fr13th 2007-06-29
2007-07-13
$./fr13th 2007-07-13 2008-06-13$ ./fr13th
2011-05-13

• Would a 2013-9-13 output be ok for the first example? – J B Feb 16 '11 at 16:05
• Do you mean we can decide whether we want to take the date as an argument or from STDIN or that we need to support both? – sepp2k Feb 16 '11 at 16:58
• @sepp2k You can decide, you don't need to support both, the user just needs a way to input a date. – Daniel Standage Feb 16 '11 at 18:06
• @JB Yeah, since there are several other solutions that do address all of the requirements, I wouldn't accept your response as the solution even if it was the shortest. That doesn't mean your response wasn't informative...but yeah, dealing with an inconsistent date format would be frustrating. – Daniel Standage Feb 16 '11 at 20:50
• Well this one is not really possible with golfscript because it doesn't know today's date*. It also doesn't have a date library so would likely be quite a large answer anyway. (*you can use ruby eval to get it, but then might as well use ruby date lib too) – gnibbler Feb 16 '11 at 21:21

## Windows PowerShell, 74

for($d="date$args"|iex;($d+='1').day*$d.dayofweek-65){}'{0:yyy-MM-d}'-f$d  Fairly straightforward. One perhaps confusing bit is the use of "Get-Date$args" | Invoke-Expression to get either the current date (if $args is empty) or the date specified in $args without raising an error.

for($d="date$args"|iex;($d+=9).day*$d.dayofweek-65){}'{0:yyy-MM-d}'-f$d  Takes ages, though ... this doesn't increment the datetime by a whole day each iteration but instead only 900 nanoseconds. But two bytes shorter. ## 67-byte variant: for($d="date $args"|iex;($d+='1').day*$d.dayofweek-65){}'{0:d}'-f$d


Oh, and it can be made into 65 bytes just like the 72-byte version.

History:

• 2011-02-17 00:33 (92) First attempt.
• 2011-02-17 00:35 (85) Improved getting an initial date.
• 2011-02-17 00:37 (79) Compared the product instead of day and day of week individually. Admittedly stolen from Ventero.
• 2011-02-17 00:40 (76) Pulled the first line into the for. Comparison just as subtraction instead of -eq which saves another two bytes.
• 2011-02-17 00:53 (75) Unix date format string is a bit shorter.
• 2011-02-17 11:42 (74) Reverted to the default date pattern but yyy-MM-d suffices (since the year is always longer than three characters and the day is always 13. Thanks to Ty Auvil for this.
• Why are you passing "date $args" to iex? Try just (date$args) instead. – Iszi Dec 11 '13 at 0:26
• @Iszi: This is used to implement the "If user provides no start date, use today as the start date." rule. If you pass an empty array or $null to Get-Date you'll get an error, not the current date. "date$args"|iex however, resolves to either the date given in $args or the current date, which is just what we want here. – Joey Dec 11 '13 at 7:05 ## bash, 75 until set date +%F -d$1+day
date -d$1|grep -q '^F.* 13' do : done echo$1


This is a bit locale-sensitive; if it fails on your machine, try exporting LC_ALL=C beforehand.

$bash fri13th.sh 2013-05-09 2013-09-13$ bash fri13th.sh 2007-06-29
2007-07-13
$bash fri13th.sh 2007-07-13 2008-06-13$ bash fri13th.sh
2011-05-13


## Ruby, 96 75 characters

require"date"
d=Date.parse(gets||"thu")+1
d+=1 while d.wday*d.day!=65
$><<d  Takes the date from stdin. To not specify a date press ctrl-d. Thanks very much for Ventero's help. Ungolfed: require "date" # Date.parse("thu") will return this week's thursday date = Date.parse(gets || "thu")+1 date += 1 while d.wday * d.day != 5 * 13$stdout << date


Sample IO:

$ruby fr13th.rb 2013-05-09 2013-09-13$ ruby fr13th.rb
2007-06-29
2007-07-13
$ruby fr13th.rb 2007-07-13 2008-06-13$ ruby fr13th.rb
2011-05-13

• d.wday*d.day==65 is 4 characters shorter. And you should be able to replace Date.today.to_s with "thu" – Ventero Feb 16 '11 at 19:30
• Actually using a loop instead of an iterator shortens the code to 76 characters: require"date";d=Date.parse($*[0]||"thu")+1;d+=1 while d.wday*d.day!=65;$><<d. And you could read the date from stdin with gets instead of $*[0] to save another character (enter EOF to get the default behavior). – Ventero Feb 17 '11 at 0:06 • @Ventero: Very nice, thanks. – sepp2k Feb 17 '11 at 6:11 ## C#, 185 Based on Andrew Koester's C# solution, but heavily modified along the way. I eventually arrived at a solution similar to my PowerShell solution: using System;class P{static void Main(string[]a){var n=a.Length>0?DateTime.Parse(a[0]):DateTime.Now;for(;(n=n.AddDays(1)).Day*(int)n.DayOfWeek!=65;);Console.Write("{0:yyy-MM-d}\n",n);}}  ## Perl (and others), 114 for(($y,$m,$d)=(shift//date +%F)=~/\d+/g,$d>12&&$m++;$m >12&&($y++,$m=1),cal$m $y!~/14$/m;$m++){}say"$y-$m-13"  Perl 5.10 or later, run with -E 'code here' or -M5.010 file. Needs date (from coreutils for Linux) and cal (from util-linux) Sample run: $ perl -M5.010 fr13.pl 2013-05-09
2013-9-13
$perl -M5.010 fr13.pl 2007-06-29 2007-07-13$ perl -M5.010 fr13.pl 2007-07-13
2008-6-13
$perl -M5.010 fr13.pl 2011-5-13  I'm not sure when the leading zero for months before October is kept. It's obviously lost when the year rolls over; it seems to be kept when the answer is just next month. Let's call that undefined behavior--hey, this is golfing! BASH #!/bin/bash from=$1
if [ "$from" = "" ]; then from=date +%Y-%m-%d fi i=1 while [ "$isFri" = "" ] || [ "$is13" = "" ] do isFri=date -d "${from} ${i} days" | grep Fri is13=date -d "${from} ${i} days" +%Y-%m-%d | grep "\-13" ((i++)) done ((i--)) date -d "${from} ${i} days" +%Y-%m-%d  CONCEPT USED: $ date -d "2011-02-16 2 days" +%Y-%m-%d
2011-02-18


SAMPLE I/O

:~/aman> ./fr13th.sh
2011-05-13
:~/aman> ./fr13th.sh 2013-05-09
2013-09-13
:~/aman> ./fr13th.sh 2007-06-29
2007-07-13
:~/aman> ./fr13th.sh 2007-07-13
2008-06-13


## C#

240 characters. C# needs a "run inside of a function only" mode!

using System;class P{static void Main(string[] a){var n=DateTime.Now;if(a.Length>0)DateTime.TryParse(args[0],out n);while(true){n=n.AddDays(1);if((n.Day==13)&&(n.DayOfWeek==(DayOfWeek)5))break;}Console.WriteLine(n.ToString("yyyy-MM-dd"));}}


Un-golfed:

using System;

class P
{
static void Main(string[] a)
{
var n = DateTime.Now;
if (a.Length > 0) DateTime.TryParse(args[0], out n);
while (true)
{
if ((n.Day == 13) && (n.DayOfWeek == (DayOfWeek)5)) break;
}
Console.WriteLine(n.ToString("yyyy-MM-dd"));
}
}


Test output

\Debug> f13.exe 2013-05-09
2013-09-13

\Debug> f13.exe 2007-06-29
2007-07-13

\Debug> f13.exe 2007-07-13
2008-06-13

\Debug> f13.exe
2011-05-13


# D: 227 Characters

import std.datetime,std.stdio;void main(string[]a){auto d=a.length<2?cast(Date)(Clock.currTime()):Date.fromISOExtendedString(a[1]);for(;d.dayOfWeek!=DayOfWeek.fri||d.day!=13;d+=dur!"days"(1)){}writeln(d.toISOExtendedString());}


More Legibly:

import std.datetime, std.stdio;

void main(string[] a)
{
auto d = a.length < 2 ? cast(Date)(Clock.currTime()) : Date.fromISOExtendedString(a[1]);

for(; d.dayOfWeek != DayOfWeek.fri || d.day != 13; d += dur!"days"(1)) {}

writeln(d.toISOExtendedString());
}


The fun part is that while D's std.datetime makes this sort of code very easy to write, it's also incredibly verbose - due primarily to the precise (and therefore long) function names. So, the usability and maintainability of the code is very high, but it's code golfability is rather low.

## Python - 166 chars

Reads from stdin, so you need to feed a blank line if you want todays date

from datetime import*
D=datetime
e=timedelta(1)
I=raw_input()
d=e+(I and D.strptime(I,"%Y-%m-%d")or D.now())
while(d.weekday()+1)*d.day-65:d+=e
print d.strftime("%F")

• Unless I'm missing something this does not address the 4th requirement (if no date is provided, start from today). – Daniel Standage Feb 16 '11 at 21:06
• @Daniel, missed that one. 26 strokes later... – gnibbler Feb 16 '11 at 21:16
• Blast from the past sorry :) If we join our solutions, we get to a collaborative 144 chars (see below!) :) – Roberto Dec 12 '13 at 2:00

## SQLite, 374 characters

(Line breaks added here for readability; not included in the count.)

Requirement to "Allow user to provide a start date either as a command line argument or through STDIN" omitted due to technical limitations.

CREATE TABLE R(N UNIQUE);
INSERT INTO R VALUES(0);
INSERT INTO R VALUES(1);
REPLACE INTO R SELECT A.N*2048|B.N*1024|C.N*512|D.N*256|E.N*128|F.N*64|
G.N*32|H.N*16|I.N*8|J.N*4|K.N*2|L.N FROM
R A,R B,R C,R D,R E,R F,R G,R H,R I,R J,R K,R L;
CREATE TABLE F AS SELECT DATE('2000-01-13','+'||N||'months') AS D
FROM R WHERE STRFTIME('%w',D)='5';
SELECT MIN(D) FROM F WHERE D>DATE('now');


The first 4 statements create a table (R) with a single column containing all the integers from 0 to 4095.

The 5th statement builds a table (F) of all Friday the 13ths between 2000-10-13 and 2340-12-13.

The 6th statement simply returns the first Friday the 13th after the current (UTC) date.

• The Gregorian calendar has a 400-year cycle, not 340 years. Or am I missing something here? – Joey Feb 17 '11 at 17:27
• It doesn't handle years outside the range 2000-2340. That was just an arbitrary choice. – dan04 Feb 18 '11 at 3:54

# PHP - 103

(brute force)

<?for($d=date_create(@$argv[1]);$d->modify('next fri')&&$d->format(@d)-13;);die($d->format("Y-m-d\n"));  Ungolfed: <?$d = new DateTime(@$argv[1]); while ($d->modify('next fri')) {
if ($d->format('d') == 13) { die($d->format("Y-m-d\n"));
}
}


Test:

$php 979.php 2013-05-09 2013-09-13$ php 979.php 2007-06-29
2007-07-13
$php 979.php 2007-07-13 2008-06-13$ php 979.php
2011-05-13

• You can save up 1 character by changing != to -. Also you can save up 2 characters by moving up the $d->modify('next fri') in the increment section of the loop. – HoLyVieR Feb 16 '11 at 19:25 • I need to modify to next friday before the loop, in case the given date is already a friday 13 :-) (or even just 13) – Arnaud Le Blanc Feb 17 '11 at 13:20 • Use -r and You don´t need the tag. Use the default config with -n and You don´t need @. \n is unnecessary. echo instead of die saves another byte. strtotime instead of Date class can save one or two more. – Titus Mar 1 '17 at 21:15 ## C#, 206 194 characters Update This is a slightly different take on the problem, so I left my other attempt here in full. using System:class p{static void Main(string[]a){var n=a.Length>0?DateTime.Parse(a[0]):DateTime.Now;for(;(n=n.AddDays(5-(int)n.DayOfWeek).AddDays(7)).Day!=13;);Console.Write("{0:yyy-MM-d}",n);}}  Here, I'm finding the "current" week's Friday and then incrementing by 7 until I find one that's a 13. I also used Joey's for loop and output formatting to shave a few characters. Ungolfed: using System; class p { static void Main(string[] a) { var n = a.Length > 0 ? DateTime.Parse(a[0]) : DateTime.Now; for (; (n = n.AddDays(5 - (int)n.DayOfWeek).AddDays(7)).Day != 13; ) ; Console.Write("{0:yyy-MM-d}", n); } }  Original: This is similar to Andrew's above, but there were enough differences I decided to post a separate answer rather than comment and suggest edits. using System;class p{static void Main(string[]a){var n=a.Length>0?DateTime.Parse(a[0]):DateTime.Now;do n=n.AddDays(1);while(!(n.Day==13&&n.DayOfWeek+""=="Friday"));Console.Write(n.ToString("yyyy-MM-dd"));}}  Ungolfed: using System; class p { static void Main(string[] a) { var n = a.Length > 0 ? DateTime.Parse(a[0]) : DateTime.Now; do { n = n.AddDays(1); } while (!(n.Day == 13 && n.DayOfWeek + "" == "Friday")); Console.Write(n.ToString("yyyy-MM-dd")); } }  ## R, 113 characters f="%Y-%m-%d";o=format;a=c(as.Date(scan(,""),f),Sys.Date())[1];repeat{a=a+1;if(o(a,"%w%d")==513)break};cat(o(a,f))  Example runs: > f="%Y-%m-%d";o=format;a=c(as.Date(scan(,""),f),Sys.Date())[1];repeat{a=a+1;if(o(a,"%w%d")==513)break};cat(o(a,f)) 1: 2007-06-29 2: Read 1 item 2007-07-13 > f="%Y-%m-%d";o=format;a=c(as.Date(scan(,""),f),Sys.Date())[1];repeat{a=a+1;if(o(a,"%w%d")==513)break};cat(o(a,f)) 1: Read 0 items 2013-12-13 > f="%Y-%m-%d";o=format;a=c(as.Date(scan(,""),f),Sys.Date())[1];repeat{a=a+1;if(o(a,"%w%d")==513)break};cat(o(a,f)) 1: 2013-12-13 2: Read 1 item 2014-06-13  # Perl 6, 69 bytes $_=Date.new(@*ARGS[0]//Date.today);.++while .day*.day-of-week-65;.say


Try it online!

Thanks to @ASCII-only for -5

• Invalid, needs to handle the case when the user does not provide an argument, also day-of-week==5 – ASCII-only Mar 1 '19 at 10:47
• @ASCII-only fixed – Ven Mar 1 '19 at 10:51
• Oh yeah, it also has to be a complete program, not a function – ASCII-only Mar 1 '19 at 10:55
• Might want to link to this (even better, go there, esc -> s -> g for a nicely formatted post) – ASCII-only Mar 1 '19 at 10:57
• 70 using the powershell answer – ASCII-only Mar 1 '19 at 11:04

Javascript

F13=function(x){
z=function(x){return (''+x).replace(/^(.)$/,'0$1')}
D=x?new Date(x):new Date(),Z=864e5,X=D.getDay()%7,X+=+D+(X?Z*(5-X):0);
do{
X+=Z*7;
D=new Date(X);
}while(D.getDate()!=13)
return D.getFullYear()+"-"+z(D.getMonth()+1)+"-"+z(D.getDate());
}


ps: yeah, I know, I broke the first rule (couldn't be just a function)

Tests on javascript shell

F13("2013-05-09") // 2013-09-13
2013-09-13
F13("2007-06-29") // 2007-07-13
2007-07-13
F13("2007-07-13") // 2008-06-13
2008-06-13
F13() //2011-05-13
2011-05-13

• +1 Fight the elitist general purpose language favoring STDIN rule. – mootinator Feb 17 '11 at 17:22

## T-SQL 359285 253 Characters

CREATE PROCEDURE f13(@d DateTime=null)AS
SET @d=ISNULL(@d,GETDATE())
;WITH d AS
(SELECT @d+1 d
UNION ALL SELECT d+1 FROM d
WHERE DATEPART(dw,d)<>6 OR DAY(d)<>13)SELECT CAST(d AS DATE) FROM d
WHERE DATEPART(dw,d)=6 AND DAY(d)=13
OPTION (MAXRECURSION 999)


I just wanted to lay the smack down on the SQLite solution with my non-clever verbose date function using T-SQL procedure.

Update: My original fear that doing a day increment would take more space than a month increment was very incorrect.

Test results (SSMS):

f13 '2013-05-09';
GO

f13 '2007-06-29';
GO

f13 '2007-07-13';
GO

f13;
GO
--

d
----------
2013-09-13

d
----------
2007-07-13

d
----------
2008-06-13

d
----------
2011-05-13


## Another Javascript, 153

I post another javascript answer because I can't comment the first...

a=new Date(process.argv[2]||Date.now());for(b=1;b;b=a.getDate()!=13||!/^F/.test(a))a.setTime(a.getTime()+864e5);console.log(a.toISOString().substr(0,10))


Execute with nodeJS :

$node fr13th 2013-12-13$ node fr13th 2007-06-29
2007-07-13

$node fr13th 2013-05-09 2013-09-13  # Python 3.3, 166 characters import datetime as d t=input() t=d.date(*map(int,t.split()))if t!=""else d.date.today() while 1: t+=d.timedelta(1) if t.day==13and t.weekday()==4: print(t);break  Input is in the format 2013 1 1, >>> ================================ RESTART ================================ >>> 2013 1 1 2013-09-13  or just press enter to use today's date (would be 2013/12/11 for this output) >>> ================================ RESTART ================================ >>> 2013-12-13  # (there is actually a mix of my solution and @gnibbler 's that counts 144 chars) import datetime as d t=input() t=d.date(*map(int,t.split()))if t!=""else d.date.today() while t.day*t.weekday()-65: t+=d.timedelta(1) print(t)  The very nice line while t.day*t.weekday()-65: is from @gnibbler's solution. # Japt, 35 bytes ÐUªKs3 ¯A @e ¶5©D¶Uf}a@f1Uf Ä s3 ¯A  -8 bytes thanks to @ASCIIOnly! Try it! • Invalid output format... – ASCII-only Mar 1 '19 at 10:06 • 36? – ASCII-only Mar 1 '19 at 10:08 • Yeah, I'm working on it :) Apparently toISOString converts to UTC which changes the date – dana Mar 1 '19 at 10:08 • How does it change the date? Does K store time as local time? – ASCII-only Mar 1 '19 at 10:14 • Fixed, 39 (well, kinda. It outputs the correct result for today at UTC (AFAICT) and that's good enough for me. Don't want to mess with timezones more than I already am) – ASCII-only Mar 1 '19 at 10:19 # Swift 4, 310 bytes import Foundation let (u,f)=(Calendar.current,DateFormatter()) f.dateFormat="yyyy-MM-dd" var t={(x:Date)->Int in let c=u.dateComponents([.weekday,.day],from:x);return c.weekday!*c.day!},d=readLine().map{f.date(from:$0)!} ?? Date()
while t(d) != 65{d=u.date(byAdding:.day,value:1,to:d)!}
print(f.string(from:d))


Try it online!

-4 thanks to TagTaco.

Alas...:

• needs Foundation for Date/Calendar.
• Swift doesn't allow Ints to be used as Bool.
• The shorthand enum syntax is helpful, though not that much.
• Space is required around ??.
• != also needs spacing, lest it's interpreted as an unwrapping.

VB.net (96c*)

Entry

Function NextFridayThe13th(d As Date) As Date
While d.DayOfWeek<>DayOfWeek.Friday
End While
While d.Day<>13
End While
Return d
End Function

• I think the CodeGolf count for vb.net shouldn't include the function signature, closing end function and the return. So it just makes it about the internal implementation.

So my scoring is broken down as so

While d.DayOfWeek<>DayOfWeek.Friday    '35c
End While                              ' 9c  57c
While d.Day<>13                        '15c  72c
End While                              ' 9c  95c
Return d                               ' 1c  96c


# Rebol, 136

d: any[do system/script/args now]until[d: d + 1 all[d/day = 13 d/weekday = 5]]print format/pad[4"-"-2"-"-2]reduce[d/year d/month d/day]


Ungolfed:

d: any [do system/script/args  now]

until [
d: d + 1
all [d/day = 13 d/weekday = 5]
]

print format/pad [4 "-" -2 "-" -2] reduce [d/year d/month d/day]


Example usage:

$rebol friday13th.reb 2013-05-09 2013-09-13$ rebol friday13th.reb
2014-06-13


# Java 8, 200 197 bytes

interface M{static void main(String[]a){java.time.LocalDate z=null,r=a.length<1?z.now():z.parse(a[0]);for(;(r=r.plusDays(1)).getDayOfWeek().getValue()*r.getDayOfMonth()!=65;);System.out.print(r);}}


Explanation:

Try it here (remove the argument to use the current date).

interface M{                        // Class
static void main(String[]a){      //  Mandatory main-method
java.time.LocalDate z=null,     //   LocalDate to reduce bytes when using static calls
r=a.length<1?                  //   If no argument is given:
z.now()                     //    Start at the current date
:                            //   Else:
z.parse(a[0]);              //    Start at the date of the first argument
for(;(r=r.plusDays(1))          //   Before every iteration, go to the next day
//   Loop as long as:
.getDayOfWeek().getValue()
//    the 1-indexed day of the week (Friday = 5)
*r.getDayOfMonth()         //    multiplied by the day of the month
!=65;                       //    is not 65
//    (5 and 13 are primes, so only 5*13 results in 65)
);                              //   End of loop
System.out.print(r);            //   Print the result Friday the 13th
}                                 //  End of main-method
}                                   // End of class


NOTE: Java's default format when printing is already yyyy-MM-dd.

# 05AB1E, 141 bytes

gĀi'-¡ëžežfžg)}V[Y2ô0Kθ4ÖUD2Qi\28X+ë<7%É31α}‹iY¬>0ëY1¾ǝDÅsD12‹i>1ë\1Dǝ¤>2}}ǝVYUÐ3‹12*+>13*5÷s3‹Xα©т%D4÷®т÷©4÷®·()O7%6QYн13Q*#}YRεDgi0ì]'-ý


05AB1E doesn't have any builtins for Date objects or calculations. The only builtin regarding dates it has is today's year/month/day/hours/minutes/seconds/microseconds.

So because of that, almost all of the code you see are manual calculations to go to the next day, and calculating the day of the week.

Mostly derived from my 05AB1E answer in The Work Day Countdown challenge (which is why I edited that one about an hour ago when I came across a bug..)

Input is a string in the format dd-MM-yyyy (but output is in the format yyyy-MM-dd, since it's one of the rules of the challenge).

Explanation:

gĀi        # If an input is given:
'-¡    '#  Split it by "-"
ë        # Else:
že      #  Push today's day
žf    #  Push today's month
žg  #  Push today's year
) #  Wrap them into a single list
}V       # After the if-else statement: pop and store it in variable Y
[          # Start an infinite loop
Y2ô0Kθ4ÖUD2Qi\28X+ë<7%É31α}‹iY¬>0ëY1¾ǝDÅsD12‹i>1ë\1Dǝ¤>2}}ǝV
#  Go to the next day
#  (see my linked The Work Day Countdown answer for an explanation)
#  Calculate the day of the week (0 = Saturday, 1 = Sunday, ..., 6 = Friday)
#  (see my linked The Work Day Countdown answer for an explanation)
6Q        #  Check if the day of the week is a Friday
Yн        #  Push the days of the current date
13Q     #  Check if it's the 13th
*         #  And if both checks are truthy:
#        #   Stop the infinite loop
}YR        # After the infinite loop: push the resulting date-list, and reverse it
ε          # Map each value to:
Dgi       #  If it's only a single digit:
0ì     #   Prepend a leading "0"
]          # Close both the if-statement and map
'-ý      '# Join the result by "-"
# (and output the result implicitly)