COBOL Y2K Redux


36

在20世纪90年代,COBOL电脑工程师摸索出了一种通过将它们转换为延长六位数的日期字段YYYDDD,其中YYYyear - 1900DDD是一年中的一天[001 to 366]。此方案可以将最长日期延长到2899-12-31

在2898年,工程师们开始恐慌,因为他们已有900年历史的代码库将要失败。从2898年开始,他们只是使用自己的时间机器将一个单独的Codeinator发送到1998年,并使用了该算法,并实现了尽可能广泛地实现它的任务:

请使用一种方案PPQQRR,在这种情况下,如果它是1900年代01 ≤ QQ ≤ 12的标准YYMMDD日期,但如果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

您面临的挑战是编写一个程序或函数以接受输入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
“但是如果可以避免的话,不要在COBOL中编程。” - 编程之道
tsh


1
@ user202729,因为yymmdd多年来没有工作>=2000,这就是Y2K崩溃的全部要点。
JAD

2
@Adám-出于对I / O非常挑剔的COBOL的精神,我不得不说它必须采用ISO yyyy-mm-dd格式。

4
@Giuseppe-秉承COBOL的精神,它并不能真正区分字符串和数字,是的!如果您可以输入前导零,例如001300

Answers:


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. 初始检查是通过SQL函数进行的ISDATE()。(此功能的行为根据语言设置而变化,在我的english-us服务器上可以正常工作)。请注意,这只是对有效性的检查,如果我们尝试直接解析它,它将映射250101为2025-01-01,而不是1925-01-01。
  2. 如果字符串正确地解析为日期,请19在前面加上钉子(而不是更改服务器级别的年截止设置)。最终日期转换将在最后结束。
  3. 如果字符串没有解析为日期,则将其转换为数字。我能找到的最短数学是8700*PP + QQRR - 1300,它避免了(很长)SQL SUBSTRING()函数。此数学运算将检查提供的样本,我非常确定这是正确的。
  4. 使用DATEADD添加许多天2000-01-01,可缩短至 2000
  5. 取得最终结果(来自步骤2的字符串或来自步骤4的DATETIME),并将CONVERT()其转换为pure DATE

我曾以为我发现一个有问题的日期:000229。这是解析只有日期不同的19XX VS 20XX(因为2000年是闰年,但1900年不是,因为怪异闰年例外)。因此,尽管如此,000229它甚至也不是一个有效的输入(如上所述,因为1900年不是a年),所以不必考虑。


好东西。太糟糕了ISDATE,不返回布尔值,或者不能将整数隐式转换为布尔值,IIF否则可以节省两个字节。

@YiminRong是的,SQL中的隐式强制转换是反复试验的,并且在某些其他非常相似的函数中的工作方式不同。我很幸运,我不必在将它们LEFT()RIGHT()函数结果相乘之前将其结果显式转换为整数,
否则

1
我想你可以通过替换删除多余的字符-1300,'2000'-935,'1999'
拉兹万·索科尔

好主意,@ 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年1月1日之前的日期(例如000101681231
Jonathan Allan '18年

2
@JonathanAllan:很好,谢谢。现在应该修复(遗憾的是需要再增加5个字节...)
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

通过将输入字符串分成三个2个字符的子字符串,您还可以节省9个字节
Arnauld

@Arnauld我最初是在我的机器上尝试此操作的。但这不起作用,因为我的时区是UTC + 8。但这至少适用于TIO。
tsh

由于我们通过语言的实现来定义语言(此处为“在TIO上运行的Node.js”),因此它真的无效吗?
Arnauld

对于防弹版本,您可以这样做以节省1个字节。
Arnauld


2

ABAP,173171字节

通过进一步优化输出节省了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.

WRITE尽管内部格式为YYYYMMDD,但ABAP的Date类型的奇数属性在使用时的格式应为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

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

在线尝试!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.