[Question]
  [
In the 1990s, COBOL computer engineers worked out a way to extend six-digit date fields by converting them to `YYYDDD` where `YYY` is the `year - 1900` and `DDD` is the day of the year `[001 to 366]`. This scheme could extend the maximum date to `2899-12-31`. 
In the year 2898, the engineers started panicking because their 900 year old code bases were going to fail. Being from the year 2898, they just used their time machine to send a lone Codeinator to the year 1998 with this algorithm and the task of getting it implemented as widely as possible:
> 
> Use a scheme `PPQQRR` where if `01 ≤ QQ ≤ 12` then it's a standard `YYMMDD` date in the 1900s, but if `QQ > 12` then it represents the days after `2000-01-01` in base 100 for `PP` and `RR` but base 87 for `QQ - 13`.
> 
> 
> 
This scheme extends far beyond year 2899 and is also backwards compatible with standard dates, so no modifications of existing archives are required.
Some examples:
```
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
```
Your challenge is to write a program or function to accept input as `PPQQRR` and output as an ISO date `YYYY-MM-DD`. Input method can be parameter, console or command line, whatever is easiest.
For your amusement, here is a noncompeting solution in 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.
```
  
[Answer]
# T-SQL, ~~99~~ 98 bytes
```
SELECT CONVERT(DATE,IIF(ISDATE(i)=1,'19'+i,
       DATEADD(d,8700*LEFT(i,2)+RIGHT(i,4)-935,'1999')))FROM t
```
Line break is for readability only. Thank goodness for implicit casting.
Input is via a pre-existing table **t** with `CHAR` column **i**, [per our IO rules](https://codegolf.meta.stackexchange.com/questions/2447/default-for-code-golf-input-output-methods/5341#5341).
Goes through the following steps:
1. Initial check is via the SQL function `ISDATE()`. (The behavior of this function changes based on language settings, it works as expected on my `english-us` server). Note this this is just a check for validity, if we tried to parse it directly, it would map `250101` as 2025-01-01, not 1925-01-01.
2. If the string parses correctly as a date, tack `19` on the front (rather than change the server-level year cutoff setting). Final date conversion will come at the end.
3. If the string does *not* parse as a date, convert it to a number instead. The shortest math I could find was `8700*PP + QQRR - 1300`, which avoids the (very long) SQL `SUBSTRING()` function. This math checks out for the provided samples, I'm pretty sure it is right.
4. Use `DATEADD` to add that many days to `2000-01-01`, which can be shorted to `2000`.
5. Take that final result (either a string from step 2, or a DATETIME from step 4), and `CONVERT()` it to a pure `DATE`.
I thought at one point that I found a problematic date: `000229`. This is the only date which parses *differently* for 19xx vs 20xx (since 2000 was a leap year, but 1900 was not, due to [weird leap-year exceptions](https://en.wikipedia.org/wiki/Leap_year#Algorithm)). Because of that, though, `000229` isn't even a valid input (since, as mentioned, 1900 was not a leap year), so doesn't have to be accounted for.
[Answer]
# [R](https://www.r-project.org/), 126 bytes
```
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'))
```
[Try it online!](https://tio.run/##bc7NasMwDADg@54iMIztJt4kq03k0tz2EiNkYBobeugPbQp5@9QJ7Id0QgcJfUK6jrEe4/207w/nkxoKXw/iXSDAl7Jb0GIqi672t7cP3wctD1Eq39h2h1R06uJvfVDoQpkPupDiUxxFJ3Wa@IbaPO2u1MwNks65WvkG2wQtABjAlFLrMarUIqDOXrMwXMK@D122zdB9o5eoSkZLz6Jkg9bQJJz7Vzj3I9IRAliI31dmwbBxTwLZQGVgnQRVjMhLwX@uuDkWYk2Mk7A0PgA "R – Try It Online")
* -5 bytes thanks to @Giuseppe suggestion to take a numeric input instead of string
[Answer]
# [JavaScript (SpiderMonkey)](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Releases/45), 103 bytes
```
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]
```
[Try it online!](https://tio.run/##Pc4xT4QwGMbx3U/RjfYs770vjTnQFBddHHTQjZBcqeVEOUpoo7j41fHwEp/pt/yT5918mmCnboxpGLtXNx398OG@l1YvQZeD@2J3JjoOALwyspG21gGOJto3vgXYHoRsSspuq8wpiZI3KalLs8l3YkOI6Y@tr9cspVMoBET/8Pz0yAWEse/i/mVfYb1EF6I1wQWmWZUUBWWKEskSRFKIZ@V4VaxSu5woX1X8LalvLv57aP10b07PZqZLZv0QfO@g9wc@S9byWQix/AI "JavaScript (SpiderMonkey) – Try It Online")
---
`.toJSON` will failed on a UTC+X timezone. This code works, but longer (+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])))
```
[Answer]
# [Python 2](https://docs.python.org/2/), 159 bytes
```
from datetime import*
def f(s):D=datetime;p,q,r=map(int,(s[:2],s[2:4],s[4:]));return str(q>12and D(2000,1,1)+timedelta(100*(q-13+87*p)+r)or D(1900+p,q,r))[:10]
```
[Try it online!](https://tio.run/##VdDBjoMgEADQ8/YruAkKyQy4FWy6p/6F8WCipiarIrKHfr0Ltpu1hIQJbzKTGfvw93mS29a7eSRt4zs/jB0ZRjs7n57aric9XVl5u/7ZxfKFu@vYWDpMntO1KmXN10qWeXzysmbs4jr/4yayekeXL5TN1JIblQDAkSPLYp22@/YNRYCULgJVpovUssyx2YVUNADZ3oixqkSotz7828Xxx9iSYSJVlYRqCJhwksRsARhuUnMSBA@CRzlrlOolZy1QCvUSY/7FmKOENgogShzgrQ9o@DRPQS2gEJA/RRUaUe@i36uZ/UTJlcYoUiV1XZ4@rAv73GckYUge9h5itv0C "Python 2 – Try It Online")
[Answer]
## ABAP, ~~173~~ 171 bytes
Saved 2 bytes by further optimizing the output
According to the legends, an SAP customer in the early 21st century once said:
> 
> After a nuclear war of total destruction, the one thing remaining will be SAPGUI.
> 
> 
> 
He was right. Today, in 2980, there is no more C++, no more COBOL. After the war everyone had to rewrite their code in SAP ABAP. To provide backwards compatibility to the leftovers of the 2800's COBOL programs, our scientists rebuilt it as a subroutine in 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.
```
It can be called by a program like this:
```
REPORT z.
  PARAMETERS date(6) TYPE c. "Text input parameter
  PERFORM x USING date.      "Calls the subroutine
```
---
Explanation of my code:
```
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's Date type has the odd property to be formatted as DDMMYYYY when using `WRITE` - might be locale dependent even - despite the internal format being YYYYMMDD. But when we use a substring selector like `d(4)` it selects the first 4 characters of the *internal* format, hence giving us YYYY.
**Update**: The output formatting in the explanation is now outdated, I optimized it by 2 bytes in the golfed version:
```
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
```
[Answer]
# [Kotlin](https://kotlinlang.org), 222 bytes
Hard coded Calendar field names constants to save 49 bytes.
```
{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))}}
```
[Try it online!](https://tio.run/##lVf/UiJJEv6fp8ghwhhwaKTxFxjDRDiCLrsqiDgbxsX9UXYX2CvdjdWNyho@wL7HPdm9yNyXWUXjzOpdHGFId1VlVuaXX/7gLs1nUfJ9a5OOjFa5DqnRaDVaTZqkhvLbKKMgDTVN09mEgls1m@lkqg9Kt3k@zw62tniT9@pZroI7/YQj2K8Habx1v9BZHqVJtuXv7bf3mqVSP4FGTX673chqdDT4OjiF9ni@yLUh6I0SrU1Gj6m5gx3pIidFj2pJeUr6KddJSFn05IXRNMophK00ifQszOhmCTXJgzZ5lEz5iphFrq@vu90uPd5qo/mF4Atfv9TKkAcrGg1S0MmH3FaIy9LJ@tQ/Gg2fVW3v7f2zTmNGIwugXuO@xSxcWcXnY/UUxYvY2gWRZqvd9vymt@3XC8dFJzZaNXldewzwDEM/V0kU3LETNzpQi0zzucgQmyrCKS6VeNyoTAMpdm2aitcpTVQ0q9NXza8Tk8Zv3LmkPxZZTtAcOtV5FLPxwS1MYSUZO6RoluL1CDdFicqZCelaG@LXoscov7X8ULNpavAWC5p8KlfZHeM41blEBOGK4vkMuCXspYLhUahnS36ap1kW3cxAqRLhcwWf1Qrk4fDiYjRyEYwmhGD8@69/0cWFfPlNviyB9o8Zy@S4XpkQoT47Q0glENGKcQ1m3A0YBTWQ//JKmoyeGw2/84IE0DdhTjYbjYbX8PHHmhhz8hEKTo3hUNyFeaxVtlr7sgP1YNc2wv6aMJYqGYJkENxlCtlVaNqiSZDMUqgK7h7hRyapoXIGx6JdeMiuwR0cTlKK0zCaRIGSVGPU9VOUCezKIKoPoIkCfEbfLyKjQ5h1mYo9ikOSAXcHM@fItXd25nW7Jfjtw2kBzgFAnkdxlAjJJdsSvlHNLNDZYjpFuiO6SMZf63TIhaLESpwa/5UaHU6RQQzZ22J7Lb@5LWJ7LZtDIga2qJv0QZfa7dX@KsesdS4F/2Yd3PG3EbfX8WSBP7VJ3w53iYvgbpsl/JbX2PcaOyIRLIyBaqt1e7/l@y16leo/mCG4LDKOhCtFlgownz9EO9stn@Wa2@/Jucg4udJ1ujDrIixFK6VH5B7nzNykU6NiAgMniyRg93lbBYGeg/bJnMtptlLJjEOBdYsqof7lwN68ZkGd@iIV6/w2Rd3BqRuNGoVbNOCqMdBZCnbiSnA1Zp3oJbqGjIUm1GM2UassQojBu2OcW7ILKkYB4mJQI5vanL9JmjDhtVAXahfiAdJO@oTX2gVT@93e@bh/3D86HPcH59Ttf@tf4qEupWM4GpyMDs@8PgzvHo573tHg/FtvZA9g4fCn878PRr/1z0@8y/FgdHjSo8ve0bjYBEPGNOwfUbvSqhZLV39f6tK3w9OrHn20Uf1YJ9mR3V0aOoGmE3DLF28vj35ahvrjHw5cuwM7P8qdva2u@2oZ4Bz1ulej3k8g9I9hzOAYZ6Ukjn/pnRcqzgbfenR8dS6wUP983DvpjbzBscfoVjhZOLurNB7QuBA6GpwNr8Y9QNWBP6L5kxTNTapU3FVcHqtYRsHcBES8xq/jd26WYOJaZ0HlSq48Lk53@5fD08NrKnfBugMqAyaoPKayVwY0xWNXHkWqd3rZe0/cb5edTSJ1sX507lgN512vj@CAPEMaXQHNza0SmlxqcvpDPag66DurHylkKkp2qbS1RT3pACh1SIyMuY1aPVPxTajqJWRskbWVUOzoJ3kVGD5zX4T0V0xnd64/SWNzHXleo/uapLNx4xDSdmJl7jmzUOO5ryF5/e3aKwUZLZdxHIbcs2KVWwm0FDvBSelA@mHB7sPuLDfITebNAwrrHMaxpi2fieAW718tbvjFsnHLbgk9uHJPn5kFAmbZb280mqFX/CvX7aUV652pOhAGMN88Rpn@0RGp2yilXIhcb81SK@FmKFpFgoKZyqRuYjiRnSBFSQ@c/6yxTr9ruuU@K5MWnxFgpdyhBfOY4LRn6kHTThvNCw35oLikft07HHX82nrhbHA@/qXTrFkxjlaxxezu7NbpBPYw4nJHAA8zLETOLtj7q0oWyiwJauEv/qvQTlvpZMJHwSZuZcIFKxTIQC9n3omjngGeZ4kBhylAmAq7gE/f2VKxYQrquEfyvkb481erMKSyW6PKfLO1/@neQ1Q3EedPxgV3Y@etyAZ8QcWvoovIU7P6ya8VOWnXdqus4oV9iSalF5jBeTRGN6HQRNxf7I8UvW6KNpViFSUVZaaIyaExavn5Ulz@Ui3S6VQSb90p31BkMZlQx0o0m00b5@/P4QGS0/siWdAJXQII/e2b0Fx43wnlOZpU7j8Dl/9G9PsaAOOAPEsoOu8E4lUQGjWf3y38b6D/v5B/BXyB98vLd/F2DKaBPqH7QWVTzU4KKD16CuyZxRg6AtQXi1CUM2g5JNeUErmOqDrFaFCpfvhQz1PA5zg1R1zyWVIpbzT2ZAbeyApDWbZGE/muVosakGB25ZkGYavJjDxDtMWaVbKHeqIWszyrC3swGge3VNHGpOYAP@JM@qgwU1edlYUFX1Vox6Sam75Waj6Uq4U/iD/yv4M5J8sHk0rZ9sByjcp21uUnO76W12wu24FVTskkap94wuQnO0f@eJ4/5Wo9VnN6Bq4Oshc5wlytFD9v2KCqE/1/0HSJhXCV5IFz5vt/AA "Kotlin – Try It Online")
]