COBOL Y2K เปลี่ยนสี


36

ในปี 1990 วิศวกรคอมพิวเตอร์ COBOL ทำงานออกวิธีการขยายหกหลักฟิลด์วันโดยการแปลงพวกเขาไปยังYYYDDDสถานที่ที่YYYเป็นyear - 1900และเป็นวันของปีDDD โครงการนี้อาจขยายวันสูงสุดที่จะ[001 to 366]2899-12-31

ในปี 2898 วิศวกรเริ่มตื่นตระหนกเนื่องจากรหัสฐาน 900 ปีของพวกเขากำลังจะล้มเหลว ตั้งแต่ปี 2898 พวกเขาใช้เครื่องย้อนเวลาเพื่อส่ง Codeinator ที่โดดเดี่ยวไปยังปี 1998 ด้วยอัลกอริธึมนี้

ใช้โครงการPPQQRRซึ่งถ้า01 ≤ QQ ≤ 12แล้วมันเป็นมาตรฐานYYMMDDวันในปี 1900 แต่ถ้าQQ > 12แล้วมันหมายถึงวันหลังจากที่2000-01-01ในฐาน 100 PPและRRแต่ฐาน QQ - 1387

โครงการนี้ขยายออกไปไกลเกินกว่าปี 2899 และสามารถใช้ร่วมกับวันที่มาตรฐานได้ดังนั้นจึงไม่จำเป็นต้องทำการปรับเปลี่ยนที่เก็บถาวรที่มีอยู่

ตัวอย่างบางส่วน:

PPQQRR  YYYY-MM-DD
000101  1900-01-01  -- minimum conventional date suggested by J. Allen
010101  1901-01-01  -- edge case suggested by J. Allen
681231  1968-12-31  -- as above
991231  1999-12-31  -- maximum conventional date
001300  2000-01-01  -- zero days after 2000-01-01
008059  2018-07-04  -- current date
378118  2899-12-31  -- maximum date using YYYDDD scheme
999999  4381-12-23  -- maximum date using PPQQRR scheme

ความท้าทายของคุณคือการเขียนโปรแกรมหรือฟังก์ชั่นที่จะยอมรับการป้อนข้อมูลเป็นและเอาท์พุทเป็นวันที่PPQQRR ISO YYYY-MM-DDวิธีการป้อนข้อมูลสามารถเป็นพารามิเตอร์คอนโซลหรือบรรทัดคำสั่งสิ่งที่ง่ายที่สุด

เพื่อความสนุกของคุณนี่คือโซลูชั่นที่ไม่ใช่การแข่งขันใน COBOL-85:

IDENTIFICATION DIVISION.
    PROGRAM-ID. DATE-CONVERSION.
DATA DIVISION.
    WORKING-STORAGE SECTION.
    01 T PIC 9(8).
    01 U PIC 9(8).
    01 D VALUE '999999'. 
        05 P PIC 9(2).
        05 Q PIC 9(2).
        05 R PIC 9(2).
    01 F.
        05 Y PIC 9(4).
        05 M PIC 9(2).
        05 D PIC 9(2).
PROCEDURE DIVISION.
    IF Q OF D > 12 THEN
        MOVE FUNCTION INTEGER-OF-DATE(20000101) TO T
        COMPUTE U = R OF D + 100 * ((Q OF D - 13) + 87 * P OF D) + T
        MOVE FUNCTION DATE-OF-INTEGER(U) TO F
        DISPLAY "Date: " Y OF F "-" M OF F "-" D OF F
    ELSE
        DISPLAY "Date: 19" P OF D "-" Q OF D "-" R OF D 
    END-IF.
STOP RUN.

4
"แต่อย่าเขียนโปรแกรมในภาษาโคบอลถ้าคุณสามารถหลีกเลี่ยงได้" - The Tao of Programming
tsh


1
@ user202729 เพราะyymmddใช้งานไม่ได้นานหลายปี>=2000นั่นคือจุดรวมทั้งหมดของการล่มสลายของ Y2K
JAD

2
@ Adám - ด้วยจิตวิญญาณของภาษาโคบอลซึ่งมีความยุ่งเหยิงมากในการเขียน I / O ฉันต้องบอกว่ามันต้องอยู่ในyyyy-mm-ddรูปแบบISO

4
@Giuseppe - ในจิตวิญญาณของ COBOL ซึ่งไม่ได้แยกความแตกต่างระหว่างสตริงและตัวเลขใช่! 001300ให้คุณสามารถป้อนศูนย์ชั้นนำเช่น

คำตอบ:


5

T-SQL, 99 98 ไบต์

SELECT CONVERT(DATE,IIF(ISDATE(i)=1,'19'+i,
       DATEADD(d,8700*LEFT(i,2)+RIGHT(i,4)-935,'1999')))FROM t

การขึ้นบรรทัดใหม่มีไว้เพื่อให้สามารถอ่านได้เท่านั้น ขอบคุณพระเจ้าที่หล่อโดยปริยาย

การป้อนข้อมูลผ่านทางตารางที่มีอยู่ก่อนทีกับCHARคอลัมน์ผม , ต่อกฎ IO ของเรา

ทำตามขั้นตอนต่อไปนี้:

  1. ISDATE()การตรวจสอบเบื้องต้นคือผ่านฟังก์ชั่น SQL (พฤติกรรมของฟังก์ชั่นนี้เปลี่ยนไปตามการตั้งค่าภาษาใช้งานได้ตามที่คาดไว้ในenglish-usเซิร์ฟเวอร์ของฉัน) โปรดทราบว่านี่เป็นเพียงการตรวจสอบความถูกต้องหากเราพยายามแยกวิเคราะห์โดยตรงมันจะแมป250101เป็น 2025-01-01 ไม่ใช่ 1925-01-01
  2. หากสตริงแยกวิเคราะห์ได้อย่างถูกต้องเป็นวันที่ให้ตะปู19ที่ด้านหน้า (แทนที่จะเปลี่ยนการตั้งค่า cutoff year ระดับเซิร์ฟเวอร์) การแปลงวันสุดท้ายจะสิ้นสุดลง
  3. หากสตริงไม่ได้แยกวิเคราะห์เป็นวันที่ให้แปลงเป็นตัวเลขแทน คณิตศาสตร์ที่สั้นที่สุดที่ฉันสามารถหาได้คือ8700*PP + QQRR - 1300ซึ่งหลีกเลี่ยงSUBSTRING()ฟังก์ชันSQL (ยาวมาก) คณิตศาสตร์นี้ตรวจสอบตัวอย่างที่ให้มาฉันค่อนข้างแน่ใจว่ามันถูกต้อง
  4. การใช้งานDATEADDที่จะเพิ่มที่จำนวนวันที่จะ2000-01-01ซึ่งสามารถ shorted 2000ไป
  5. ใช้เวลาที่ผลสุดท้าย (ทั้งสตริงจากขั้นตอนที่ 2 หรือ DATETIME จากขั้นตอนที่ 4) และมันจะบริสุทธิ์CONVERT()DATE

000229ฉันคิดว่าเมื่อถึงจุดหนึ่งที่ผมพบว่าวันที่มีปัญหา: นี่เป็นวันเดียวที่แยกวิเคราะห์แตกต่างกันสำหรับ 19xx กับ 20xx (ตั้งแต่ปี 2000 เป็นปีอธิกสุรทิน แต่ 1900 ไม่ได้เนื่องจากข้อยกเว้นปีอธิกสุรทินแปลก ) เพราะเหตุนั้นแม้ว่า000229จะไม่ได้เป็นข้อมูลที่ถูกต้อง (ตั้งแต่ดังที่กล่าวไว้ 1900 ไม่ได้เป็นปีอธิกสุรทิน) ดังนั้นจึงไม่ต้องคิด


สิ่งที่ดี. มันแย่มากที่ISDATEจะไม่ส่งคืนบูลีนหรือจำนวนเต็มไม่สามารถแปลงเป็นบูลีนโดยนัยได้IIFมิฉะนั้นคุณสามารถบันทึกสองไบต์ได้

@YiminRong ใช่การคัดเลือกโดยนัยใน SQL นั้นเป็นการทดลองและข้อผิดพลาดมากและทำงานแตกต่างกันไปในบางฟังก์ชันที่คล้ายกันมาก ฉันโชคดีที่ผมไม่ได้มีที่จะโยนอย่างชัดเจนของฉันLEFT()และRIGHT()ผลการทำงานเพื่อจำนวนเต็มก่อนคูณพวกเขาที่จะได้จริงๆ messed ขึ้นนับไบต์ของฉัน
BradC

1
ฉันคิดว่าคุณสามารถเอาตัวละครพิเศษโดยการแทนที่ด้วย-1300,'2000' -935,'1999'
Razvan Socol

ไอเดียเจ๋ง ๆ @RazvanSocol ฉันพยายามย้อนกลับทวีคูณอีก 365 วัน แต่น่าเสียดายที่ไม่พบอะไรที่สั้นไปกว่านั้น
BradC

5

R , 126 ไบต์

function(x,a=x%/%100^(2:0)%%100,d=as.Date)'if'(a[2]<13,d(paste(19e6+x),'%Y%m%d'),d(a[3]+100*((a[2]-13)+87*a[1]),'2000-01-01'))

ลองออนไลน์!

  • -5 ไบต์ขอบคุณสำหรับข้อเสนอแนะ @Giuseppe เพื่อรับอินพุตเป็นตัวเลขแทนที่จะเป็นสตริง

4
ล้มเหลวในการป้อนข้อมูลที่เป็นตัวแทนของวันที่ก่อนเดือนมกราคม 1969 แรก (เช่น000101หรือ681231)
Jonathan Allan

2
@JanathanAllan: เห็นดีขอบคุณ ตอนนี้มันควรจะคงที่ (น่าเสียดายที่กำหนด 5 ไบต์ more ... )
digEmAll

4

JavaScript (SpiderMonkey) , 103 ไบต์

s=>new Date(...([a,b,c]=s.match(/../g),b>12?[2e3,0,(b-13+a*87)*100-~c]:[a,b-1,c])).toJSON().split`T`[0]

ลองออนไลน์!


.toJSONจะล้มเหลวในเขตเวลา UTC + X รหัสนี้ใช้งานได้ แต่นานกว่า (+ 11bytes):

s=>Intl.DateTimeFormat`ii`.format(new Date(...([a,b,c]=s.match(/../g),b>12?[2e3,0,(b-13+a*87)*100-~c]:[a,b-1,c])))

คุณสามารถบันทึก 13 ไบต์.toJSON()ด้วย
Arnauld

และคุณสามารถบันทึกได้อีก 9 ไบต์โดยแยกสตริงอินพุตออกเป็น 2 substrings สองอักขระ
Arnauld

@Arnauld ฉันเคยลองสิ่งนี้ในเครื่องของฉัน แต่มันไม่ทำงานเนื่องจากเขตเวลาของฉันคือ UTC + 8 แต่อย่างน้อยก็ใช้ได้กับ TIO
tsh

เนื่องจากเรากำหนดภาษาตามการนำไปใช้ (นี่คือ 'Node.js ที่ทำงานบน TIO') มันไม่ถูกต้องจริงหรือ
Arnauld

สำหรับเวอร์ชั่นกันกระสุนคุณสามารถทำเช่นนั้นเพื่อประหยัด 1 ไบต์
Arnauld


2

ABAP, 173 171 ไบต์

บันทึก 2 ไบต์โดยการเพิ่มประสิทธิภาพเอาต์พุต

ตามตำนานลูกค้า SAP ในช่วงต้นศตวรรษที่ 21 เคยกล่าวไว้ว่า:

หลังจากสงครามนิวเคลียร์แห่งการทำลายล้างทั้งหมดสิ่งที่เหลืออยู่ก็คือ SAPGUI

เขาพูดถูก วันนี้ในปีพ. ศ. 2980 ไม่มี C ++ อีกต่อไปไม่มี COBOL อีกแล้ว หลังสงครามทุกคนต้องเขียนรหัสใหม่ใน SAP ABAP เพื่อให้ความเข้ากันได้ย้อนหลังกับส่วนที่เหลือของโปรแกรมภาษาโคบอลของ 2,800, นักวิทยาศาสตร์ของเราสร้างขึ้นมาใหม่เป็น subroutine ใน ABAP

FORM x USING s.DATA d TYPE d.IF s+2 < 1300.d ='19'&& s.ELSE.d ='20000101'.d = d + s+4 + 100 * ( ( s+2(2) - 13 ) + 87 * s(2) ).ENDIF.WRITE:d(4),d+4,9 d+6,8'-',5'-'.ENDFORM.

มันสามารถถูกเรียกโดยโปรแกรมเช่นนี้:

REPORT z.
  PARAMETERS date(6) TYPE c. "Text input parameter
  PERFORM x USING date.      "Calls the subroutine

คำอธิบายรหัสของฉัน:

FORM x USING s.     "Subroutine with input s
  DATA d TYPE d.    "Declare a date variable (internal format: YYYYMMDD)
  IF s+2 < 1300.    "If substring s from index 2 to end is less than 1300
    d ='19'&& s.    "the date is 19YYMMDD
  ELSE.             "a date past 2000
    d ='20000101'.  "Initial d = 2000 01 01 (yyyy mm dd)

    "The true magic. Uses ABAPs implicit chars to number cast
    "and the ability to add days to a date by simple addition.
    "Using PPQQRR as input:
    " s+4 = RR, s+2(2) = QQ, s(2) = PP
    d = d + s+4 + 100 * ( ( s+2(2) - 13 ) + 87 * s(2) ).
  ENDIF.
    "Make it an ISO date by splitting, concatenating and positioning the substrings of our date.
    WRITE:             "Explanation:
      d(4),            "d(4) = YYYY portion. WRITE adds a space after each parameter, so...
      5 '-' && d+4,    "place dash at absolute position 5. Concatenate '-' with MMDD...
      8 '-' && d+6.    "place dash at absolute position 8, overwriting DD. Concatenate with DD again.
ENDFORM.

ประเภทวันที่ของ ABAP มีคุณสมบัติแปลก ๆ ที่จะจัดรูปแบบเป็น DDMMYYYY เมื่อใช้WRITE- อาจจะขึ้นอยู่กับตำแหน่งที่ตั้งแม้ - แม้ว่ารูปแบบภายในจะเป็น YYYYMMDD แต่เมื่อเราใช้ตัวเลือกสตริงย่อยd(4)มันจะเลือกตัวอักษร 4 ตัวแรกของรูปแบบภายในดังนั้นจึงให้เรา YYYY

อัปเดต : การจัดรูปแบบผลลัพธ์ในคำอธิบายล้าสมัยไปแล้วฉันปรับให้เหมาะสม 2 ไบต์ในเวอร์ชัน golfed:

WRITE:  "Write to screen, example for 2000-10-29
 d(4),   "YYYY[space]                =>  2000
 d+4,    "MMDD[space]                =>  2000 1029
 9 d+6,  "Overwrites at position 9   =>  2000 10229
 8'-',   "Place dash at position 8   =>  2000 10-29
 5'-'.   "Place dash at position 5   =>  2000-10-29

ยอดเยี่ยมฉันชอบมัน ตอนนี้สิ่งที่เราต้องการคือเวอร์ชั่นในMUMPSและเราจะอยู่รอดได้ทุกอย่าง!

1
@YiminRong ขอบคุณ! คำถามตาม COBOL ของคุณโดยทั่วไปถามอะไรแบบนี้ฉันไม่มีทางเลือก
Maz

1

Kotlinขนาด 222 ไบต์

ชื่อเขตข้อมูลปฏิทินที่เข้ารหัสแบบตายตัวยังคงบันทึก 49 ไบต์

{d:Int->val p=d/10000
val q=d/100%100
val r=d%100
if(q<13)"19%02d-%02d-%02d".format(p,q,r)
else{val c=Calendar.getInstance()
c.set(2000,0,1)
c.add(5,(p*87+q-13)*100+r)
"%4d-%02d-%02d".format(c.get(1),c.get(2)+1,c.get(5))}}

ลองออนไลน์!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.