วันของสัปดาห์ถัดไป 29 กุมภาพันธ์


14

เขียนฟังก์ชั่นที่ใช้วันที่และส่งคืนวันในสัปดาห์ของวันที่ 29 กุมภาพันธ์ถัดไปหลังจากวันที่นั้น

  • อินพุตเป็นสตริงในรูปแบบ ISO Extended: YYYY-MM-DD (เช่น 27 พฤษภาคม 2010 จะเป็น "2010-05-27")

  • ผลลัพธ์คือสตริงที่เป็นชื่อของวันในสัปดาห์ (เช่น "วันจันทร์") การใช้อักษรตัวพิมพ์ใหญ่ไม่สำคัญ แต่ให้ชื่อเต็มเป็นภาษาอังกฤษ

  • หากวันที่ที่กำหนดคือ 29 กุมภาพันธ์ให้ส่งคืนวันในสัปดาห์ของวันที่ 29 กุมภาพันธ์ถัดไป

  • ใช้การคำนวณสำหรับปฏิทินเกรกอเรียน Proleptic (ดังนั้นจะใช้การคำนวณแบบกระโดดปีเกรโกเรียนสำหรับความยาวทั้งหมด) ไม่ต้องกังวลกับปฏิทินจูเลียนหรือเมื่อมีการเปลี่ยนจากจูเลียนเป็นเกรโกเรียน เพียงแค่ถือว่า Gregorian สำหรับทุกสิ่ง

  • ฟังก์ชันควรใช้งานได้อย่างน้อยช่วง "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 จะไม่กระโดดปี
  • 1 มกราคม 0001 คือวันจันทร์

คำตอบ:


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 Taylor

@ Peter: dateมันอาจปะทะกับ เพียงลบ GNUWin32 ออกจาก PATH และควรใช้งานได้ หรือเปลี่ยนdateเป็นGet-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 Taylor

@ Peter: ฉันลอง PowerShell v2 .NET 4 ไม่เล่นเนื่องจาก PowerShell เชื่อมโยงกับรันไทม์ 2.0 ในกรณีใด ๆ ไม่ควรจะเป็นกลับมาจาก PSObject แต่Get-Date System.DateTime
Joey

มันแปลกมาก $d=Get-Date "0400-01-01"; $d++ให้ข้อความแสดงข้อผิดพลาดเกี่ยวกับการ++ไม่ถูกกำหนดใน DateTime การแทนที่แบบเดียวกัน++ด้วย+=1หรือ+="1"หรือ+='1'แสดงข้อความแสดงข้อผิดพลาดเกี่ยวกับ PSObject และเพียงแค่ได้+"1"ผล
Peter Taylor

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-01testcase
  • แก้ไข 2: (97 -> 91) Date.parse อนุญาตให้ระบุวันที่ของการปฏิรูปปฏิทินเช่นกัน
  • แก้ไข 3: (91 -> 87) ใช้แลมบ์ดาแทนฟังก์ชั่น ขอบคุณDogbert !
  • แก้ไข 4: (87 -> 85) ลบช่องว่างที่ไม่จำเป็นออก ขอขอบคุณอีกครั้งDogbert !

4
การทดสอบล้มเหลวสำหรับ "0001-01-01" วันที่ของรูบี้นั้นแรงเกินไปมันต้องใช้วันที่ของจูเลียนเข้ามาด้วย
steenslag

@Ventero def * ทำอะไรได้บ้าง ไม่เคยเห็นมาก่อน
steenslag

@steenslag: ขอบคุณแก้ไข testcase นั้น เพียงแค่กำหนดฟังก์ชั่นที่เรียกว่าdef* *ด้วยวิธีนี้ฉันไม่ต้องการช่องว่างระหว่างdefและชื่อฟังก์ชัน
Ventero

1
คุณไม่สามารถกำหนดแลมบ์ดาแทนได้ใช่ไหม a = -> {... }
Wile E. Coyote

1
นอกจากนี้ยังไม่จำเป็นต้องมีพื้นที่ใด ๆ หลังจากช่วงเวลาสั้น ๆ
Wile E. Coyote

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

เนื่องจากฉันสร้างการลบเกิน 2 เดือนนับจาก 0001-01-01 แม้ว่าฉันจะใช้ประเภทข้อมูลที่ถูกต้องฉันยอมแพ้ในการสร้างสิ่งที่สั้นและถูกต้องสำหรับคำถามนี้ O_o Trixsy questionzes
mootinator

ฉันชอบที่จะเห็นโซลูชั่น T-SQL เหล่านี้ :)
Steve

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")พิมพ์วันที่ในสถานที่ปัจจุบันแม้ว่าไม่ใช่ภาษาอังกฤษ
Joey

165 chars => 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 ();}
Stephan Schinkel

ปรับปรุงเพิ่มเติมเป็น 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

3

Bash, 96 ไบต์

ขอบคุณ Peter ... รุ่น golfed สูงมากไบต์ 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

:-) ในขณะที่เราพูดถึงการแข่งขันดิบของฉันมากกว่าทุบตี! ... ด้วยเหตุผลบางอย่างฉันไม่เล่นซอมากกับทุบตี .. พวกเขามีข้อผิดพลาดง่าย! .. ขอบคุณสำหรับคำแนะนำของคุณ .. อัปเดต!
Aman ZeeK Verma

1
ความดิบกับทุบตีไม่มีข้อแก้ตัวสำหรับการใช้ชื่อตัวแปรสี่ตัวอักษร: P
Peter Taylor

ใช่ครับฉันเข้าใจคุณแล้ว
Aman ZeeK Verma

2

Perl, ไม่มีไลบรารีวันที่: 160 159 155

ย่อย f {($ y, $ m) = แยก / - /, @ _ ​​[0], 2; $ y ++ ถ้า ($ m> '02 -28 '); $ y = ($ y + 3)% 400 >> 2; $ Y + = $ Y && ($ Y 25%); @ r = (อังคาร, Wednes, พฤหัสบดี, ศุกร์, Satur อาทิตย์จันทร์);! @ R [(5 * $ Y - ($ / y 25 และ 3))% 7] "วัน";.}

ประโยชน์ที่แท้จริงของไลบรารีวันที่เหล่านี้คือการผลักดันความยาวของชื่อของวันให้ผู้อื่น

ในทางกลับกันฉันคิดว่านี่เป็นวิธีแก้ปัญหาเดียวที่ทำงานได้โดยไม่คำนึงถึงสถานที่


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

Ungolfed:

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

ฉันยอมรับ downvotes แต่คุณช่วยอธิบาย "the necro is real" และลิงก์ไปยังคำถามที่พบบ่อยซึ่งอธิบายประเด็นของคุณได้ไหม? ฉันไม่คิดว่าฉันจะชนะ แต่คิดว่ามันน่าสนใจที่จะเห็นว่า Java สามารถทำได้อย่างไร ให้ Java 8 ฉันดูรหัสกอล์ฟว่ามี "คลาสน้ำหนัก" กับการแข่งขันทันที Java แทบจะไม่ชนะ Ruby หรือ Python ทันที
Michael Easter

OP ห้ามห้องสมุดบุคคลที่สามดังนั้นในปี 2011 โซลูชัน Java จะไม่เป็นที่พอใจเนื่องจากไม่มีใครสามารถใช้ห้องสมุด Joda Time ยอดนิยมได้ อย่างไรก็ตาม Java 8 (ปล่อยตัวมีนาคม 2014) มีห้องสมุด DateTime วิว-310 - 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)]

Ungolfed:

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

coreutils ของ GNU, 71 ไบต์

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

การค้นหาเชิงเส้นในอีก 8 ปีข้างหน้า (กรณีที่เลวร้ายที่สุดได้รับ 2096-02-29) Sed ค้นหาและส่งออกบรรทัดแรกที่ตรงกับ 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.