下2月29日的星期几


14

编写一个带有日期并返回该日期之后的下一个2月29日的星期几的函数。

  • 输入是ISO扩展格式的字符串:YYYY-MM-DD(例如,2010年5月27日为“ 2010-05-27”)。

  • 输出是一个字符串,它是星期几的名称(例如“ Monday”)。大写字母无关紧要,但是请使用英文全名。

  • 如果给定的日期是2月29日,则返回下一个 2月29日的星期几。

  • 使用Proleptic Gregorian Calendar的计算(因此,它使用整个公历的Gregorian year年计算)。不用担心朱利安日历或何时从朱利安切换为公历。只要为所有事情假设格里高利安。

  • 该功能至少应在“ 0001-01-01”至“ 2100-01-01”范围内工作。

  • 可以随意使用您选择的语言提供的任何标准库,但不要使用第三方库,除非您希望将该代码包含在解决方案中。

  • 最短的代码(最少的字符)获胜。

例子:

  • func("0001-01-01") -> "Sunday"
  • func("1899-12-03") -> "Monday"
  • func("1970-01-01") -> "Tuesday"
  • func("1999-07-06") -> "Tuesday"
  • func("2003-05-22") -> "Sunday"
  • func("2011-02-17") -> "Wednesday"
  • func("2100-01-01") -> "Friday"

(而且,您不必命名该函数func

提示:

  • 请记住,以00结尾的年份不能被400整除,这并不是leap年。
  • 0001年1月1日为星期一。

Answers:


7

Windows PowerShell,65

非常坦率的。

filter f{for($d=date $_;($d+='1').day*$d.month-58){}$d.dayofweek}

和往常一样,如果我们愿意等待很长时间才能完成,则可以舍弃两个字节:

filter f{for($d=date $_;($d+=9).day*$d.month-58){}$d.dayofweek}

测试:

> '0001-01-01','1899-12-03','1970-01-01','1999-07-06','2003-05-22','2011-02-17','2100-01-01'|f
Sunday
Monday
Tuesday
Tuesday
Sunday
Wednesday
Friday

历史:

  • 2011-02-18 00:06(65)第一次尝试。

这项工作需要什么路径?我的路线中有GnuWin日期,这很麻烦。
彼得·泰勒

@Peter:可能与发生冲突date。只需从PATH中删除GNUWin32,它就可以工作。或更改dateGet-Date(这种后备行为仅在未找到命令的情况下才起作用-只需使用即可检查gcm date)。无论如何,我不认为此脚本有一个特殊的问题,因为GNUWin32并不是任何标准Windows安装的一部分。
Joey

我问的原因是因为我已经尝试使用get-date并收到错误消息,Method invocation failed because [System.Management.Automation.PSObject] doesn't contain a method named 'op_Addition'.是否需要PS2或.Net 4或其他?
彼得·泰勒

@Peter:我尝试了PowerShell v2。由于PowerShell已链接到2.0运行时,因此.NET 4不会发挥作用。在任何情况下,不应该有从PSObject回来Get-Date,但一个System.DateTime
乔伊,

很奇怪 $d=Get-Date "0400-01-01"; $d++给出有关++未在DateTime上定义的错误消息。相同的替换+++=1+="1"+='1'给出关于PSObject的错误消息。并且+"1"有效。
彼得·泰勒

5

Ruby 1.9,85个字符

f=->a{require"date";d=Date.parse(a,0,0)+1;d+=1until d.day*d.month==58;d.strftime"%A"}

简单的解决方案。用调用函数f[args]

  • 编辑:(87-> 97)修复了 0001-01-01测试用例。
  • 编辑2:(97-> 91)Date.parse也允许指定日历改革的日期。
  • 编辑3:(91-> 87)使用Lambda代替函数。谢谢Dogbert
  • 编辑4:(87-> 85)删除不必要的空格。再次感谢,多伯特

4
测试用例“ 0001-01-01”失败。Ruby的Date太强大了,它考虑了朱利安日期。
steenslag

@Ventero def *是做什么的?以前没看过。
steenslag'2

@steenslag:谢谢,修复了该测试用例。def*只是定义了一个名为的函数*。这样,我def和函数名之间就不需要空格。
Ventero '02

1
您不能只定义一个lambda吗?a =-> {...}
Dogbert

1
另外,strftime之后不需要任何空间。
Dogbert

3

T-SQL 166185个字符

CREATE PROCEDURE f29 (@d DATETIME) AS
DECLARE @i int
SET @i=YEAR(DATEADD(M,-2,@d)+3)
SET @i=@i+(4-@i%4)
IF @i%100=0 AND @i%400<>0 SET @i=@i+4
SELECT DATENAME(W,CAST(@i AS CHAR)+'-2-29')

我已经搞砸了T-SQL日期函数,所以我想为什么不...

原始解决方案不正确...

为了使该策略生效,实际上是我要做的事情:

CREATE PROCEDURE f29 (@d DATE) AS
DECLARE @i int
SET @i = YEAR(@d)
BEGIN TRY 
SET @i=YEAR(DATEADD(D, 3, DATEADD(M,-2,@d)))
END TRY
BEGIN CATCH
END CATCH
SET @i=@i+(4-@i%4)
IF @i%100=0 AND @i%400<>0 SET @i=@i+4
SELECT DATENAME(W,CAST(@i AS CHAR)+'-2-29')

鉴于我从0001-01-01创建溢出减去2个月就算我用正确的数据类型我放弃创造一些短期有效这个问题。哦 Trixsy疑问。
mootinator 2011年

我喜欢看到这些T-SQL解决方案。:)
史蒂夫

3

C#,176

Func<String,String>f=(d)=>{DateTime n;for(n=DateTime.Parse(d).AddDays(307);!(DateTime.IsLeapYear(n.Year));n=n.AddYears(1)){}return new DateTime(n.Year,2,29).ToString("dddd");};

您可以使用正常的函数定义保存8个字节:string f(string d){...}
Joey

.ToString("dddd")但是,以当前语言环境打印日期,而不是英语。
乔伊,

165个字符=>字符串f(字符串d){var n = DateTime.Parse(d).AddDays(307); while(!(DateTime.IsLeapYear(n.Year)))n = n.AddYears(1);返回(新的DateTime(n.Year,2,29))。DayOfWeek.ToString();}
Stephan Schinkel 2014年

进一步改进为127个字符:string f(string d){var n=DateTime.Parse(d).AddDays(1);return DateTime.IsLeapYear(n.Year)&&n.DayOfYear==60?n.DayOfWeek+"":f(n+"");}
Patrik Westerlund 2014年

3

Bash,96个字节

谢谢彼得...高尔夫版本,96字节:

i=1;until [ `date -d"$1 $i days" +%m-%d` = "02-29" ];do((i++));done
date -d "${1} ${i} days" +%A

旧版本,229字节

#!/bin/bash
from=$1
i=1
while [ "$isFeb" = "" ] || [ "$is29" = "" ]
do
isFeb=`date -d "${from} ${i} days" | grep Feb`
is29=`date -d "${from} ${i} days" +%Y-%m-%d | grep "\-29"`
((i++))
done
((i--))
date -d "${from} ${i} days" +%A

样品I / O

:~/aman>./29Feb.sh 0001-01-01
Sunday
:~/aman>./29Feb.sh 1899-12-03
Monday
:~/aman>./29Feb.sh 1970-01-01
Tuesday

如果没有设置默认时区,可能必须设置TZ,我在一些在线IDE上学习了cyberciti.biz/faq/…的同时
Aman ZeeK Verma 2011年

1
你要去打高尔夫球吗?; p您可以用i=0;d=;until [ `date -d"$1 $i days" +%m-%d` = "02-29" ];do((i++));done
Peter Taylor

:-)正如我们已经讨论过的关于bash的原始方法一样!...出于某种原因,我对bash不太喜欢。.它们是如此容易出错!..感谢您的建议..已更新!
2011年

1
使用bash的原始性不能成为使用四个字母的变量名称的借口:P
Peter Taylor

是的,先生,我明白你的意思。
2011年

2

Perl,无日期库:160159 155

sub f {($ y,$ m)= split /-/,@ _ [0],2; $ y ++ if($ m> '02 -28'); $ y =($ y + 3)% 400 >> 2; $ y + = $ y &&!($ y%25); @ r =(星期二,星期三,星期四,星期五,星期六,星期日,星期一); @ r [(5 * $ y-($ y / 25&3))%7]。“ day”;}

这些日期库的真正好处是将日期名称的长度缩短给其他人。

另一方面,我认为这是迄今为止唯一适用于任何区域的解决方案。


2

DATE和一些BASHy胶(90)

功能:

f(){ while :;do $(date -d$1+1day +'set - %F %A 1%m%d');(($3==10229))&&break;done;echo $2;}

测试:

$ for x in 0001-01-01 1899-12-03 1970-01-01 1999-07-06 2003-05-22 2011-02-17 2100-01-01 ; do f $x ; done
Sunday
Monday
Tuesday
Tuesday
Sunday
Wednesday
Friday

1

D:175个字符

S f(S)(S s){auto d=Date.fromISOExtString(s)+days(1);while(d.month!=Month.feb||d.day!=29)d+=days(1);return["Sun","Mon","Tues","Wednes","Thurs","Fri","Sat"][d.dayOfWeek]~"day";}

更清晰:

S f(S)(S s)
{
    auto d = Date.fromISOExtString(s) + days(1);

    while(d.month != Month.feb || d.day != 29)
        d += days(1);

    return ["Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Sat"][d.dayOfWeek] ~ "day";
}

用D编写非常容易,但是绝对不会赢得任何打高尔夫比赛的代码。尽管如此,在代码打高尔夫球之外,我还是希望它易于编写和理解,但比它简洁但难以编写和理解却要长。


1

Java 8-252个字符

打高尔夫球:

import java.time.*;
import java.time.format.*;
public class S{public static void main(String[] a){LocalDate d=LocalDate.parse(a[0]).plusDays(1);while(d.getMonthValue()!=2||d.getDayOfMonth()!=29){d=d.plusDays(1);}System.out.println(d.getDayOfWeek());}}

取消高尔夫:

import java.time.*;
import java.time.format.*;
public class S {
    public static void main(String[] a) {
        LocalDate d = LocalDate.parse(a[0]).plusDays(1);

        while(d.getMonthValue()!=2 || d.getDayOfMonth()!=29) {
            d = d.plusDays(1);
        }
        System.out.println(d.getDayOfWeek());
    }
}

我接受不赞成票,但可以请您解释“死灵是真实的”并链接到可以解释您观点的常见问题解答吗?我没想到我会赢,但是我认为看到Java可以做到的事情会很有趣,尤其是。给定Java8。我认为代码高尔夫具有“重量级”与完全竞争。Java很少会完全击败Ruby或Python。
迈克尔·复活节

OP禁止第三方库,因此在2011年,Java解决方案将令人不快,因为无法使用流行的Joda Time库。但是,Java 8(2014年3月发布)包含JSR-310 DateTime库-en.wikipedia.org/wiki/…。我的理由是我认为Java 8会很有趣,并且对某些读者来说可能很有趣。(如果您不是其中之一,那就很好:仍然有这个职位。)
Michael Easter

1

Rebol-78

f: func[d][system/locale/days/(until[d: d + 1 d/day * d/month = 58]d/weekday)]

取消高尔夫:

f: func [d] [
    system/locale/days/(
        until [
            d: d + 1
            d/day * d/month = 58
        ]
        d/weekday
    )
]

用法示例(在Rebol控制台中):

>> f 0001-01-01
== "Sunday"

>> f 2100-01-01
== "Friday"

1

PHP,104字节

function f($s){for($y=$s-(substr($s,5)<"02-29");!date(L,$t=strtotime(++$y."-2-1")););return date(l,$t);}

分解

for($y=$s-;                 // "-" casts the string to int; decrement year if ...
    (substr($s,5)<"02-29")  // ... date is before feb 29
    !date(L,                        // loop while incremented $y is no leap year
        $t=strtotime(++$y."-2-1")   // $t=feb 01 in that year (same weekday, but shorter)
    );
);
return date(l,$t);          // return weekday name of that timestamp

date(L)1对于leap年,0否则
date(l):表示星期几的全文


0

GNU coreutils,71个字节

f(){
seq -f "$1 %gday" 2921|date -f- +'%m%d%A'|sed 's/0229//;t;d;:;q'
}

未来8年的线性搜索(最坏情况,给出2096-02-29)。Sed查找并输出与2月29日匹配的第一行。

我很惊讶地发现 t;d;:;q/[01]/d;q,尽管命令数是两倍,但它比测试以查看数字是否仍为()短。

测验

我为困难的极端情况添加了额外的测试行:

for i in 0001-01-01.Sunday 1899-12-03.Monday \
    1970-01-01.Tuesday     1999-07-06.Tuesday \
    2003-05-22.Sunday      2011-02-17.Wednesday 2100-01-01.Friday \
    2000-02-28.Tuesday     2000-02-29.Sunday    2000-03-01.Sunday   2096-02-29.Friday
do
    printf "%s => %s (expected %s)\n" ${i%.*} $(f ${i%.*}) ${i#*.}
done
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.