코볼 Y2K redux


36

1990 년대에, COBOL 컴퓨터 엔지니어로 변환하여 6 자리 날짜 필드를 확장하는 방법 밖으로 일 YYYDDD경우 YYY입니다 year - 1900DDD년의 일이다 [001 to 366]. 이 체계는 최대 날짜를까지 연장 할 수 있습니다 2899-12-31.

2898 년에 엔지니어들은 900 년 된 코드베이스가 실패하기 때문에 당황했습니다. 2898 년부터이 알고리즘과 가능한 한 광범위하게 구현해야하는 작업으로 타임머신을 사용하여 1998 년에 고독한 코디네이터를 보냈습니다.

하는 제도를 사용 PPQQRR하는 경우 01 ≤ QQ ≤ 12다음 표준의 YYMMDD1900 년대에 날짜를하지만, 경우에 QQ > 12그것은 후에 일을 나타냅니다 2000-01-01위한베이스 (100) PPRR뿐만 기본 87 QQ - 13.

이 체계는 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

당신의 도전은 PPQQRRISO 날짜로 입력 과 출력 을 받아들이는 프로그램이나 함수를 작성하는 것 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
"하지만 피할 수 있다면 COBOL로 프로그래밍하지 마십시오." - 프로그래밍의 타오
tsh


1
@ user202729 yymmdd는 수년 동안 작동하지 않기 때문에 Y2K 디바 클 >=2000의 요점입니다.
JAD

2
@ Adám-매우 까다로운 wrt I / O 인 COBOL의 정신에서 ISO yyyy-mm-dd형식 이어야 합니다.

4
@Giuseppe-문자열과 숫자를 실제로 구분하지 않는 COBOL의 정신에서 그렇습니다! 선행 0을 입력 할 수있는 경우 (예 :) 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

줄 바꿈은 가독성을위한 것입니다. 암시 적 캐스팅에 감사합니다.

입력은 기존의 테이블을 통해입니다 tCHAR내가 , 우리의 IO의 규칙에 따라 .

다음 단계를 수행하십시오.

  1. 초기 점검은 SQL 기능을 통해 이루어 ISDATE()집니다. (이 기능의 동작은 언어 설정에 따라 달라지며 english-us서버에서 예상대로 작동 합니다). 이것은 유효성 검사에 불과합니다. 직접 구문 분석하려고하면 2501011925-01-01이 아니라 2025-01-01로 매핑 됩니다.
  2. 문자열이 날짜로 올바르게 구문 분석되는 경우 19서버 레벨 연도 컷오프 설정을 변경하지 말고 앞면을 고정 하십시오. 최종 날짜 변환이 끝납니다.
  3. 문자열이 날짜로 구문 분석 되지 않으면 대신 숫자로 변환하십시오. 내가 찾을 수있는 가장 짧은 수학 8700*PP + QQRR - 1300은 (매우 긴) SQL SUBSTRING()함수 를 피합니다 . 이 수학은 제공된 샘플을 확인합니다. 정확합니다.
  4. 사용 DATEADD에 많은 일 추가 2000-01-01로 단락 할 수 있습니다 2000.
  5. 최종 결과 (2 단계의 문자열 또는 4 단계의 DATETIME)를 가져 CONVERT()와서 순수하십시오 DATE.

한 시점에서 문제가있는 날짜를 발견했다고 생각했습니다 000229. 이것은 19xx 대 20xx에 대해 다르게 구문 분석되는 유일한 날짜입니다 (2000 년은 윤년이지만 1900 년은 이상한 윤년 예외 로 인해 아닙니다 ). 그러나 0002291900 년이 윤년이 아니기 때문에 유효한 입력조차도 아니므로 고려할 필요가 없습니다.


좋은 물건. 너무 나쁘면 ISDATE부울을 반환하지 않거나 정수를 암시 적으로 부울로 변환 할 수 없으므로 IIF2 바이트를 절약 할 수 있습니다.

@YiminRong Yep, SQL에서의 암시 적 캐스팅은 시행 착오이며, 매우 유사한 일부 함수에서는 다르게 작동합니다. 나는 운이 내가 명시 적으로 내 캐스팅하지 않았다 해요 LEFT()그리고 RIGHT()정말 내 바이트 수 엉망 것이라고 그들을 곱 전에 정수 기능 결과를
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'))

온라인으로 사용해보십시오!

  • @Giuseppe의 제안 덕분에 문자열 대신 숫자 입력을받을 수있어 -5 바이트

4
1969 년 1 월 1 일 이전 날짜를 나타내는 입력 실패 (예 : 000101또는 681231)
Jonathan Allan

2
@JonathanAllan : 감사합니다. 이제
고쳐야

4

자바 스크립트 (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]

온라인으로 사용해보십시오!


.toJSONUTC + X 시간대에서 실패했습니다. 이 코드는 작동하지만 더 길다 (+11 바이트).

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

입력 문자열을 3 개의 2 문자 하위 문자열로 분할하여 9 바이트더 절약 할 수 있습니다 .
Arnauld

@ Arnauld 나는 원래 내 컴퓨터에서 이것을 시도하고있었습니다. 그러나 시간대가 UTC + 8이므로 작동하지 않습니다. 그러나 적어도 TIO에서는 작동합니다.
tsh

구현으로 언어를 정의하기 때문에 (여기서는 'TIO에서 실행되는 Node.js') 실제로 유효하지 않습니까?
Arnauld

방탄 버전을 할 수 있습니다 그런 식으로 할 1 바이트를 저장합니다.
Arnauld


2

ABAP, 173 171 바이트

출력을 더욱 최적화하여 2 바이트 절약

전설에 따르면 21 세기 초 SAP 고객은 다음과 같이 말했습니다.

전체 파괴의 핵전쟁 이후 남은 것은 SAPGUI가 될 것입니다.

그는 옳았다. 현재 2980 년에는 더 이상 C ++도없고 COBOL도 없습니다. 전쟁이 끝난 후 모두가 SAP ABAP에서 코드를 다시 작성해야했습니다. 2800의 COBOL 프로그램의 남은 부분에 대한 하위 호환성을 제공하기 위해 과학자들은 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의 날짜 유형에는 WRITE내부 형식이 YYYYMMDD 임에도 불구하고 사용시 로케일에 따라 달라질 수있는 홀수 속성이 DDMMYYYY로 표시됩니다 . 그러나 하위 문자열 선택기를 사용 d(4)하면 내부 형식 의 처음 4자를 선택 하므로 YYYY가 발생합니다.

업데이트 : 설명의 출력 형식이 이제 구식입니다. 골프 버전에서는 2 바이트로 최적화했습니다.

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

코 틀린 , 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.