下星期五13日


15

能预测下一个星期五的下一个最短程序是哪个月的第13天?

  • 必须是功能完整的程序(而不仅仅是函数/子例程)
  • 必须以以下格式打印日期: YYYY-MM-DD
  • 允许用户提供开始日期作为命令行参数或通过 STDIN
  • 如果用户未提供开始日期,请使用今天作为开始日期。
  • 如果开始日期是13号星期五,则程序应找到下一个 13号星期五。

如果今天(2011年2月16日)运行该程序,则应获得以下输出。

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

将一个2013-9-13输出的第一个例子行吗?
JB

您是说我们可以决定是否要以日期作为参数还是以STDIN为参数,还是需要同时支持两者?
sepp2k 2011年

@ sepp2k您可以决定,您不需要两者都支持,用户只需要输入日期的方式即可。
丹尼尔·斯坦迪奇

@JB是的,由于还有其他解决方案可以满足所有要求,因此即使是最短的解决方案,我也不会接受您的答复。这并不意味着您的回答没有提供信息...但是,是的,处理日期格式不一致会令人沮丧。
Daniel Standage

好吧,用golfscript不可能真正做到这一点,因为它不知道今天的日期*。它还没有日期库,因此无论如何可能都是一个很大的答案。(*您可以使用ruby eval来获取它,但也可以使用ruby date lib)
gnibbler

Answers:


6

Windows PowerShell,74

for($d="date $args"|iex;($d+='1').day*$d.dayofweek-65){}'{0:yyy-MM-d}'-f$d

非常坦率的。一个可能令人困惑的地方是使用"Get-Date $args" | Invoke-Expression来获取当前日期(如果$args为空)或指定的日期$args而不会引发错误。

72个字节的变体:

for($d="date $args"|iex;($d+=9).day*$d.dayofweek-65){}'{0:yyy-MM-d}'-f$d

尽管要花一些时间,但是...这不会使日期时间每次迭代增加一整天,而是仅增加900纳秒。但是要短两个字节。

67字节的变体:

for($d="date $args"|iex;($d+='1').day*$d.dayofweek-65){}'{0:d}'-f$d

这对语言环境敏感。如果在您的计算机上失败,请尝试将日期格式预先设置为ISO-8601。:-)

哦,就像72字节的版本一样,它可以变成65字节。

历史:

  • 2011-02-17 00:33(92)第一次尝试。
  • 2011-02-17 00:35(85)改进了初始日期。
  • 2011-02-17 00:37(79)分别比较产品而不是日期和星期几。承认是从Ventero偷来的。
  • 2011-02-17 00:40(76)将第一行拉入for。比较只是减法,而不是-eq节省另外两个字节。
  • 2011-02-17 00:53(75)Unix date格式的字符串短一些。
  • 2011-02-17 11:42(74)恢复为默认的日期格式,但yyy-MM-d足够了(因为年份始终长于三个字符,并且日期始终为13。这要感谢Ty Auvil。

为什么将“ date $ args”传递给iex?试一试(date $ args)。
Iszi 2013年

@Iszi:用于实现“如果用户未提供开始日期,请使用今天作为开始日期。” 规则。如果将一个空数组传递$nullGet-Date,则会得到一个错误,而不是当前日期。"date $args"|iex但是,解析为给定的日期$args 当前日期,这正是我们想要的。
乔伊,

4

bash,75岁

until set `date +%F -d$1+day`
date -d$1|grep -q '^F.* 13'
do :
done
echo $1

这对语言环境敏感。如果失败,你的机器上,尝试export荷兰国际集团LC_ALL=C提前。

$ 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

4

Ruby,96 75个字符

require"date"
d=Date.parse(gets||"thu")+1
d+=1 while d.wday*d.day!=65
$><<d

从stdin中获取日期。要不指定日期,请按ctrl-d。

非常感谢Ventero的帮助。

取消高尔夫:

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

样本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

1
d.wday*d.day==65短4个字符。而且您应该可以替换Date.today.to_s"thu"
Ventero 2011年

实际上,使用循环代替迭代器会将代码缩短为76个字符:require"date";d=Date.parse($*[0]||"thu")+1;d+=1 while d.wday*d.day!=65;$><<d。您可以从标准输入中读取日期,gets而不用$*[0]保存另一个字符(输入EOF以获取默认行为)。
Ventero '02

@Ventero:很好,谢谢。
sepp2k 2011年

3

C#,185

基于Andrew Koester的C#解决方案,但在此过程中进行了大量修改。我最终得出了一个类似于PowerShell解决方案的解决方案:

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

2

Perl(及其他)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或更高版本,使用-E 'code here'或运行-M5.010 file。需求date(来自Linux的coreutils)和cal(来自util-linux的)

样品运行:

$ 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

我不确定十月前几个月的前零是否会保留。一年过去了,它显然迷失了;答案在下个月才出现。让我们称之为未定义行为-嘿,这是打高尔夫球!


2

重击

#!/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

使用的概念:

$ date -d "2011-02-16 2 days" +%Y-%m-%d
2011-02-18

样品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

2

C#

240个字符。C#需要“仅在函数内部运行”模式!

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

未打高尔夫球:

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

测试输出

\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

2

D:227个字符

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

更清晰:

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

有趣的部分是,尽管D的std.datetime使此类代码非常易于编写,但它也非常冗长-主要是由于函数名称精确(因此很长)。因此,该代码的可用性和可维护性很高,但是它的代码可使用性却很低。


2

Python-166个字符

从stdin读取,因此如果您要今天的日期,则需要输入空白行

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

除非我缺少某些内容,否则这不能满足第4个要求(如果没有提供日期,请从今天开始)。
Daniel Standage

@Daniel,错过了那个。26招以后...
gnibbler 2011年

过去的爆炸很抱歉:)如果我们加入我们的解决方案,我们将合作144个字符(见下文!):)
Roberto

2

SQLite,374个字符

(为了方便阅读,在此处添加了换行符;不包括在计数中。)

由于技术限制,省略了“允许用户通过命令行参数或通过STDIN提供开始日期”的要求。

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');

前4条语句创建一个表(R),其中的单列包含从0到4095的所有整数。

第5条语句建立了一个表(F),该表在2000-10-13和2340-12-13之间的所有第13个星期五。

第6条语句仅返回当前(UTC)日期之后的第13个第一个星期五。


公历是400年的周期,而不是340年。还是我在这里想念什么?
乔伊,

它不能处理2000-2340范围以外的年份。那只是一个随意的选择。
dan04 2011年

2

PHP-103

(强力)

<?for($d=date_create(@$argv[1]);$d->modify('next fri')&&$d->format(@d)-13;);die($d->format("Y-m-d\n"));

取消高尔夫:

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

测试:

$ 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

1
更改!=为,最多可以保存1个字符-。您也可以通过$d->modify('next fri')在循环的增量部分中上移来节省2个字符。
HolyVieR 2011年

如果给定的日期已经是星期五13:
Arnaud Le Blanc

使用-r并且您不需要标签。与-n和一起使用默认配置@\n是没有必要的。echo而不是die保存另一个字节。strtotime而不是Date上课可以再节省一两个。
泰特斯

2

C#,206194个字符

更新资料

这是对该问题的略有不同的看法,因此我在此完全放弃了其他尝试。

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

在这里,我找到了“当前”星期的星期五,然后递增7,直到找到13。我还使用了Joey的for循环和输出格式来剃一些字符。

取消高尔夫:

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

原版的:

这与安德鲁(Andrew)的上述内容类似,但是有足够的差异,我决定发布一个单独的答案,而不是发表评论并提出建议。

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

取消高尔夫:

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

2

R,113个字符

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

示例运行:

> 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

2

Perl 6,69个字节

$_=Date.new(@*ARGS[0]//Date.today);.++while .day*.day-of-week-65;.say

在线尝试!

感谢@ ASCII-only -5


无效,还需要处理用户不提供参数时的情况,同样day-of-week==5
纯ASCII

@ ASCII只固定
法师

哦,是的,它也必须是一个完整的程序,而不是一个函数
仅ASCII格式,

可能希望链接到此(甚至更好,到那里,esc-> s-> g以获得格式正确的帖子)
仅ASCII的


1

Java脚本

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:是的,我知道,我打破了第一个规则(不能只是一个函数)

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与支持STDIN规则的精英通用语言作斗争。
mootinator

1

T-SQL 359 285 253个字符

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)

我只是想通过使用T-SQL过程的非巧妙的详细日期函数将SQLite解决方案放下。

更新:我最初担心做一天增量会比一个月增量占用更多空间, 非常不正确的。

测试结果(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

1

另一个Java脚本153

我发布了另一个JavaScript答案,因为我无法评论第一个...

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

使用nodeJS执行:

$ node fr13th
2013-12-13

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

$ node fr13th 2013-05-09
2013-09-13

1

Python 3.3,166个字符

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

输入格式为2013 1 1

>>> ================================ RESTART ================================
>>> 
2013 1 1
2013-09-13

或按Enter键即可使用今天的日期(此输出将为2013/12/11)

>>> ================================ RESTART ================================
>>> 

2013-12-13

(实际上是我的解决方案和@gnibbler的混合体,共计144个字符)

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)

非常好的一行while t.day*t.weekday()-65:来自@gnibbler的解决方案。


1

Japt,35个字节

ÐUªKs3 ¯A
@e ¶5©D¶Uf}a@f1Uf Ä
s3 ¯A

-8个字节感谢@ASCIIOnly!

尝试一下!


无效的输出格式...
仅ASCII的


是的,我正在研究它:)显然toISOString转换为UTC,它会更改日期
dana

如何更改日期?是否K将时间存储为本地时间?
–仅使用ASCII

1
已修复,为39(好吧,有点。它在UTC(AFAICT)上输出的是今天的正确结果,对我来说已经足够了。不想把时区弄得比我本来就糟
ASCII-仅

1

迅捷 4,310字节

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

在线尝试!

-4感谢TagTaco。

唉...:

  • 需要日期/日历基础。
  • Swift不允许将Ints用作Bool
  • 简写枚举语法很有帮助,尽管不是很多。
  • 周围需要空间 ??
  • != 还需要间距,以免将其解释为展开。

0

VB.net(96c *)

条目

Function NextFridayThe13th(d As Date) As Date
  While d.DayOfWeek<>DayOfWeek.Friday
    d=d.AddDays(1)
  End While
  While d.Day<>13
    d=d.AddDays(7)
  End While
  Return d
End Function
  • 我认为vb.net的CodeGolf计数不应包含函数签名结束函数返回。因此,它仅涉及内部实现。

所以我的分数就这样细分了

While d.DayOfWeek<>DayOfWeek.Friday    '35c
d=d.AddDays(1)                         '13c  48c
End While                              ' 9c  57c
While d.Day<>13                        '15c  72c
d=d.AddDays(7)                         '14c  86c
End While                              ' 9c  95c
Return d                               ' 1c  96c

0

雷伯尔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]

取消高尔夫:

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]

用法示例:

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

0

Java的8,200个 197字节

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

说明:

在此处尝试(删除参数以使用当前日期)。

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

注意:打印时Java的默认格式已经yyyy-MM-dd


0

05AB1E,141 字节

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

05AB1E没有任何内置对象可用于Date对象或计算。关于日期的唯一内置函数是今天的年/月/日/小时/分钟/秒/微秒。

因此,因此,您看到的几乎所有代码都是手动计算,可以转到第二天,并计算星期几。

主要来自我在“工作日倒计时”挑战中的05AB1E答案(这就是为什么大约一个小时前遇到错误时才编辑该原因。)

输入是采用格式的字符串dd-MM-yyyy(但输出采用格式yyyy-MM-dd,因为它是质询的规则之一)。

在线尝试验证所有测试用例

说明:

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
 Y`2ô0Kθ4ÖUD2Qi\28X+ë<731α}‹iY¬>0ëY1¾ǝDÅsD12i>1ë\1Dǝ¤>2}}ǝV
           #  Go to the next day
           #  (see my linked The Work Day Countdown answer for an explanation)
 Y`UÐ312*+>13*5÷s3Xα©т%D4÷®т÷©4÷®·()O7%
           #  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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.