次の2月29日の曜日


14

日付を取り、その日付の次の2月29日の曜日を返す関数を作成します。

  • 入力はISO拡張形式の文字列です:YYYY-MM-DD(たとえば、2010年5月27日は「2010-05-27」になります)。

  • 出力は、曜日の名前を表す文字列です(例:「月曜日」)。大文字と小文字は関係ありませんが、フルネームは英語で入力してください。

  • 指定された日付が2月29日の場合、次の 2月29日の曜日を返します。

  • Proleptic Gregorian Calendarの計算を使用します(そのため、全体の長さについてはグレゴリオうるう年の計算を使用します)。ユリウス暦について、またはユリウス暦からグレゴリオ暦への切り替えがいつ発生したかを心配しないでください。すべてについてグレゴリオを仮定してください。

  • この関数は、少なくとも「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

ヒント:

  • 400で割り切れない00で終わる年はうるう年ではないことに注意してください。
  • 0001年1月1日は月曜日です。

回答:


7

Windows PowerShell、65

かなり簡単です。

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

いつものように、完了まで長い時間待ちたい場合は、2バイトを削減できます。

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インストールの一部ではないとは考えていません。
ジョーイ

私が尋ねた理由は、すでに使用しようとして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です。
ジョーイ

とても奇妙です。DateTimeで定義され$d=Get-Date "0400-01-01"; $d++++いないことに関するエラーメッセージを表示します。PSObjectについてのエラーメッセージがorまたはorに置き換え++られます。そして機能します。+=1+="1"+='1'+"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)関数の代わりにラムダを使用します。おかげでDogbert
  • 編集4:(87-> 85)不要なスペースを削除します。どうもありがとう、ドッグバート

4
「0001-01-01」のテストケースに失敗します。Rubyの日付は強力すぎるため、ユリウス暦の日付が考慮されます。
-steenslag

@Ventero def *の機能 前に見たことがない。
-steenslag

@steenslag:ありがとう、そのテストケースを修正しました。def*という関数を定義するだけ*です。そうすればdef、関数名との間にスペースを必要としません。
ヴェンテロ

1
代わりにラムダを定義することはできませんか?a =-> {...}
ドグバート

1
また、strftimeの後にスペースは必要ありません。
ドグバート

3

T-SQL 166 185文字

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か月を差し引くオーバーフローを作成する、この質問に対して短く有効なものを作成することをあきらめます。O_o。Trixsyが質問します。
mootinator

これらの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文字=> string f(string d){var n = DateTime.Parse(d).AddDays(307); while(!(DateTime.IsLeapYear(n.Year)))n = n.AddYears(1); return (新しいDateTime(n.Year、2,29))。DayOfWeek.ToString();}
ステファンシンケル14

:また、127文字まで改善string f(string d){var n=DateTime.Parse(d).AddDays(1);return DateTime.IsLeapYear(n.Year)&&n.DayOfYear==60?n.DayOfWeek+"":f(n+"");}
パトリック・ウェスター

3

Bash、96バイト

ありがとうPeter ...高度にゴルフされたバージョン、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を設定する必要があるかもしれませんが、私はcyberciti.biz/faq/を学びました。一部のオンラインIDEでこれを行いながら
Aman ZeeK Verma

1
これをゴルフするつもりですか?; p最終行の前のすべてをi=0;d=;until [ `date -d"$1 $i days" +%m-%d` = "02-29" ];do((i++));done
Peter Taylor

:-)すでにbashに対する私の生っぽさについて議論したように!...何らかの理由で、bashをいじりません。エラーが発生しやすいです。..提案をありがとう。
アマンZeeKヴァーマ

1
bashの持つヒリヒリは4文字の変数名を使用するための言い訳にはならない:P
ピーター・テイラー

はい、ご了承ください。
アマンZeeKヴァーマ

2

Perl、日付ライブラリなし:160 159 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());
    }
}

私は下票を受け入れますが、「ネクロは本物です」とあなたのポイントを説明するFAQへのリンクを説明してもらえますか?私は勝つとは思いませんでしたが、Javaがどのようにできるかを見るのは面白いと思いました。Java 8が与えられました。私はコードゴルフを、「重量クラス」対完全競争と見なしています。JavaがRubyやPythonを完全に打ち負かすことはめったにありません。
マイケルイースター14

OPはサードパーティのライブラリを禁止しているため、2011年には、人気のあるJoda Timeライブラリを使用できなかったため、Javaソリューションは不快になります。ただし、Java 8(2014年3月にリリース)には、JSR-310 DateTimeライブラリ(en.wikipedia.org/wiki/…)が含まれています。私の理由は、Java 8は楽しく、潜在的には一部の読者にとって興味深いと思ったからです。(あなたがそれらのいずれでもない場合、結構です:まだ投稿の理由があります。)
マイケルイースター14

1

レボル-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うるう年、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コマンドが2倍多いにもかかわらず)。

テスト

難しいコーナーケース用のテスト行を追加しました。

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.