ปฏิทินแบบโรลโอเวอร์


17

นี่เป็นแรงบันดาลใจจากหนึ่งในคำถามของ Downgoat ใน Sandbox ที่ฉันแนะนำว่าเขารวมวันที่ 31 เมษายนเป็นวัน Pi สำหรับผู้ที่ใช้รูปแบบวัน / เดือนเพียงเพื่อให้เขาบอกฉันว่าไม่มีวันที่ 31 เมษายน!

กำหนดสตริงวันที่ในรูปแบบเดือน / วันที่อาจไม่ถูกต้องส่งออกวันที่ที่ถูกต้องโดยใช้โรลโอเวอร์ (โรลโอเวอร์ครั้งแรกของเดือนจากนั้นโรลโอเวอร์วัน)

ตัวอย่าง:

"15/43" - นี่เป็นวันที่ 43 ของเดือนที่ 15 อันดับแรกเราเลื่อนเดือนไปยังปีถัดไปดังนั้นเราจึงสิ้นสุดด้วย 3 (มีนาคม) ขณะนี้เนื่องจากเดือนมีนาคมมีเพียง 31 วันเราจึงเลื่อนวันพิเศษเป็นเดือนเมษายนดังนั้นเราจึงส่งออกวันที่ตามจริงเป็น"4/12" (12 เมษายน)

"3/16" - นี่คือวันที่ที่ถูกต้อง (16 มีนาคม) กลับมาเหมือนเดิม

"12/64" - อาความทรงจำที่น่ารักมากมายตั้งแต่ 64 ธันวาคม ... ธันวาคมมี 31 วันมกราคมมี 31 วันดังนั้นสิ่งที่ฉันหมายถึงคือ"2/2" (2 กุมภาพันธ์)

"19/99" - อย่างแรกคือ 19 กลายเป็น 7 (กรกฎาคม) กรกฎาคมมี 31 วันสิงหาคมมี 31 วันกันยายนมี 30 วันดังนั้นผลลัพธ์คือ"10/7" (7 ตุลาคม)

"1/99999" - หนึ่งปีมี 365 วัน 99999 (สมัย 365) = 354. วันที่ 354 ของปี"12/20"

"9999999/10" - เห็นได้ชัดว่า 9999999 (mod 12) = 3 ดังนั้นนี่คือ"3/10" (10 มีนาคม)

เกณฑ์:

เดือนที่นำเข้าเป็นจำนวนเต็ม> 0 วันที่ป้อนเป็นจำนวนเต็ม> 0 ปีไม่จำเป็นต้องระบุเนื่องจากไม่มีปีอธิกสุรทินที่ต้องจัดการ

ปรับปรุง:

อย่างที่ฉันคิดว่ามันจะทำให้ความท้าทายมากเกินไปฟังก์ชั่นปฏิทินเช่นในคลาสJava Calendarถูกแบน ฟังก์ชันการแยกวิเคราะห์ / จัดรูปแบบวันที่ยังคงได้รับอนุญาต



1
กรณีทดสอบที่สำคัญอีกอย่างหนึ่งคือมีเวลามากพอที่จะย้อนไปกว่า 8 ปีเช่นนั้นคำตอบที่ใช้บิวด์อินต้องใส่ใจกับบิวด์อินเหล่านั้นโดยใช้ปีอธิกสุรทิน
Martin Ender

โอ้คำตอบนั้น ... ฉันเพิ่งจะโพสต์คำตอบ Mathematica ซึ่งใช้ในตัว : /
Martin Ender

@ Martin ขออภัยเกี่ยวกับสิ่งนั้น;)
geokavel

สำหรับการอ้างอิงโซลูชัน Mathematica ยังคงมีความยาว 90 ไบต์ (แม้ว่าจะถูกครอบงำด้วยการประมวลผลสตริง) หากคุณต้องการเพิ่มกรณีทดสอบดังกล่าว1/99999ควรให้ผล12/19ฉันคิดว่า
Martin Ender

คำตอบ:


11

LabVIEW, 32 LabVIEW Primitives


นั่นเป็นเรื่องด่วน
Addison Crump

คุณช่วยให้ฉันมั่นใจได้ว่าไม่มีฟังก์ชั่นปฏิทินที่ใช้ที่นี่?
geokavel

สิ่งที่ดีเกี่ยวกับ LabVIEW ก็คือมันเป็นสิ่งที่ดูเหมือนจะเป็น สิ่งแรกที่สแกนตัวเลขจากสตริง 2 โมดูลนั้นกล่องเป็นโครงสร้างตัวสวิตช์ที่ให้ 28,30 หรือ 31 จากนั้นจะรวมกันเป็นสตริงอีกครั้ง
Eumel

4

C #, 269 223

string v(string n){var x=new[]{31,28,31,30,31,30,31,31,30,31,30,31};var s=n.Split('/');Func<string,int> p=int.Parse;var m=p(s[0]);var d=p(s[1]);m=m>=12?m%12:m;while(d>x[m]){d-=x[m];m=++m>=12?m%12:m;}return(m==0?1:m)+"/"+d;}

แก้ไข : แก้ไขการทำงานสำหรับกรณีเช่น 24/1, 36/1 เป็นต้นและตีกอล์ฟเล็กน้อย ขอบคุณสำหรับความคิดเห็นมีหลายสถานที่ที่ฉันบันทึกไว้เล็กน้อย!

Ungolfed:

string v(string n)
{
    var x = new [] { 31 ,28, 31, 30, 31, 30,31, 31, 30, 31, 30, 31 };

    var s = n.Split('/');
    Func<string,int> p = int.Parse;
    var m = p(s[0]);
    var d = p(s[1]);
    m = m >= 12 ? m % 12 : m;
    while (d > x[m])
    {
        d -= x[m];
        m = ++m >= 12 ? m % 12 : m;
    }
    return (m==0?1:m) + "/" + d;
}

ก่อนอื่น: ยินดีต้อนรับสู่ชุมชน! ฉันเดาว่าคุณสามารถบันทึก Bytes บางส่วนได้ด้วยการกำหนดพจนานุกรมในลูปหรือใช้ฟังก์ชั่นสวิทช์ (ไม่มี C # pro ที่นี่) การพิมพ์´m + "/" + d directly โดยตรงก็อาจช่วยได้เช่นกัน และสุดท้าย (สิ่งนี้อาจหรืออาจจะไม่ทำงาน) โดยใช้ char * แทนที่จะเป็นสตริงในอาร์กิวเมนต์
Eumel

24/1นี้ล้มเหลวในกรณีทดสอบบางอย่างเช่น
LegionMammal978

@Eumel ขอบคุณ! ใช้งานการพิมพ์โดยตรงConsole.Writeซึ่งมากกว่าreturnและใน C # ฉันจะใช้char[]แทนstringแต่เป็นจำนวนตัวอักษรเดียวกันและทำให้แยกบน/มีปัญหามากขึ้น แต่บันทึกย่อของคุณในพจนานุกรมทำให้ฉันเป็นรุ่นที่ดีกว่า!
DrewJordan

4

R, 208 182 ไบต์

m=c(31,28,31,30,31,30,31,31,30,31,30,31)
e=scan(sep="/");n=(e[1]/12-1)*12;if(!n%%12)n=12;if(n<0)n=e[1];j=e[2];while((j<-j-m[n])>0){n=n+1;if(n>12)n=1};j=m[n]+j;cat(n,j,sep="/")

รับเดือนโดยหารด้วย 12 จากนั้นวนซ้ำลบจำนวนวันของเดือนปัจจุบันจนกว่าคุณจะได้รับจำนวนลบ, ผกผันขั้นตอนสุดท้ายและพิมพ์

ในหลายบรรทัด (ต้องใช้ไฟล์และแหล่งที่มา):

m=c(31,28,31,30,31,30,31,31,30,31,30,31)
e=scan(sep="/")
n=(e[1]/12-1)*12
if(!n%%12)n=12
if(n<0)n=e[1]
j=e[2]
while((j<-j-m[n])>0){n=n+1;if(n>12)n=1}
j=m[n]+j;cat(n,j,sep="/")

นี่คือข้อความที่ฉันได้รับเมื่อพยายามเรียกใช้โปรแกรมของคุณใน R: pastebin.com/dPh1n64a
geokavel

แปลกฉันจะตรวจสอบในภายหลัง
Tensibai

ฉันยังได้รับข้อความนี้ โปรแกรมของคุณดูเหมือนจะมีปัญหากับบางเดือน มิฉะนั้นมันจะทำงาน pastebin.com/g3BCUDi8
geokavel

ขอบคุณสำหรับความคิดเห็น. ฉันอยู่บนท้องถนนจริงฉันจะแก้ไขมัน
Tensibai

1
@ Tenensai ใช่คุณไม่ดีฉันไม่ดี (ฉันควรจะจำได้ว่าข้อผิดพลาดบอกว่ามันคาดว่า "ของจริง")
plannapus

3

PHP> = 5.5, 181 ไบต์

list($m,$d)=explode("/",$argv[1]);$m%=12;$d%=365;$i=0;while($d>100)$d-=[31,28,31,30,31,30,31,31,30,31,30,31][$i++];$m+=$i;echo date_create_from_format("m/d","$m/$d")->format("n/j");

PHP เกือบรองรับโรลโอเวอร์ด้วยการแยกวิเคราะห์วันที่และคำแนะนำการจัดรูปแบบเพียงอย่างเดียว ตัวอย่างเช่น:

echo date_create_from_format("m/d","12/64")->format("n/j"); // Output: 2/2

อย่างไรก็ตามเมื่อตัวเลขใดจำนวนหนึ่งใหญ่กว่า 100 PHP จะปฏิเสธการแยกวิเคราะห์และส่งคืนข้อผิดพลาด (อาจเป็นเพราะเหตุผลบางประการ) ดังนั้นทฤษฎีที่มีคำตอบนี้ก็คือนำมันกลับไปที่ที่ PHP จะแยกวิเคราะห์แล้วส่งไปที่date_create_from_format()จะแยกมันแล้วส่งไปยัง

Ungolfed:

list($month, $day) = explode("/", $argv[1]);
$month = $month % 12;
$day = $day % 365;
$i = 0;
$days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
while($day > 31) $day -= $days[$i++];
$month += $i;
echo DateTime::createFromFormat("m/d", $month . "/" . $day)->format("n/j");

ลองออนไลน์


1
คุณต้องให้วิธีฉันใส่สตริงวันที่หรือทำให้มันเป็นฟังก์ชั่น
geokavel

GET พารามิเตอร์ไม่เป็นที่ยอมรับในฐานะที่เป็นวิธีการป้อนข้อมูลใน PHP คุณจะต้องทำให้ฟังก์ชั่นนี้และส่งผ่านการป้อนข้อมูลเป็นพารามิเตอร์ฟังก์ชั่นหรือรับข้อมูลจาก$argvหรือ STDIN
Mego

@Mego Jeeze ให้เวลาฉันในการอัพเดทคำตอบของฉันเนื่องจาก OP ไม่ได้ระบุข้อกำหนดสำหรับอินพุต - มันง่ายพอที่จะเปลี่ยน$tเป็น$argv[1]และตอนนี้มันอ่านจากอินพุตบรรทัดคำสั่ง
nickb

ข้อกำหนดการระบุ OP สำหรับอินพุตไม่เกี่ยวข้อง เรามีรายการวิธีการเริ่มต้น I / O ที่ยอมรับได้ (ซึ่งฉันเชื่อมโยง) เพื่อให้ผู้เขียนการท้าทายไม่จำเป็นต้องระบุไว้ในทุกการท้าทาย
Mego

2

JavaScript (ES6), 106 ไบต์

s=>eval('q="030101001010";p=s.split`/`;for(d=i=p[1],m=p[0]-1;i--;d>n&&(m++,d-=n))n=31-q[m%=12];m+1+"/"+d')

คำอธิบาย

s=>
  eval(`              // use eval to enable for loop without needing to write {} or return
    q="030101001010"; // q = array of 31 - days in each month
    p=s.split\`/\`;   // p = array of [ month, day ]
    for(
      d=i=p[1],       // d = day
        m=p[0]-1;     // m = month - 1
      i--;            // loop for each day, this is more iterations than needed but extra
                      //     iterations do not affect the result and it's the shortest way
                      //     to guarantee all months have been subtracted from d, it also
                      //     ensures the loop runs at least once to get m % 12
      d>n&&(m++,d-=n) // if too many days, subtract the month's days and increment month
    )
      n=31-q[m%=12];  // n = number of days in month, get m % 12
    m+1+"/"+d         // return the result
  `)

ทดสอบ


1

คำตอบที่ไม่ใช่คู่แข่ง - Bash + coreutils, 55

date -d1-$[(${1%/*}-1)%12+1]-1+$[${1#*/}-1]day +%-m/%-d

"ฟังก์ชันการแยกวิเคราะห์วันที่ / การจัดรูปแบบยังคงได้รับอนุญาตแม้ว่า" - ฉันถือว่านี่หมายถึงdateยูทิลิตี้ได้รับอนุญาต

อินพุตถูกอ่านจากบรรทัดคำสั่งเช่น:

$ ./rollovercal.sh 15/43
4/12
$ 

นี่ไม่ใช่การแข่งขันเนื่องจากคำสั่ง date ขยายออกไปเป็นอย่างนี้ซึ่งกำลังเพิ่มจำนวนวัน:

date -d1-3-1+42day +%-m/%-d

อนุญาตตราบใดที่ไม่ทำอะไรเช่นdate.add(875)เพิ่มวันโดย 875 วัน นั่นคือสิ่งที่ฉันจะทำหลังจากนั้น
geokavel

@geokavel โอ้ฉันเข้าใจแล้ว dateคำสั่งที่ขยายอย่างเต็มที่ที่นี่คือdate -d1-3-1+42day +%-m/%-dดังนั้นมันทำอย่างนั้น ฉันเดาว่านี่เป็นคำตอบที่ไม่ใช่คู่แข่ง :(
Digital Trauma
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.