| Bytes | Lang | Time | Link |
|---|---|---|---|
| 128 | Haskell | 241021T213017Z | DPD- |
| 117 | Python 3 | 240903T025930Z | Lucenapo |
| 098 | C clang | 240909T194805Z | jdt |
| 076 | JavaScript Node.js + momentjs | 240903T101110Z | doubleun |
| nan | C# .NET 6+ | 240904T120218Z | Arkane |
| 079 | JavaScript Node.js | 240902T084009Z | l4m2 |
| 058 | Charcoal | 240903T222310Z | Neil |
| 134 | Go | 240903T191837Z | bigyihsu |
| 120 | Retina 0.8.2 | 240903T175255Z | Neil |
| nan | Ruby | 240903T084423Z | G B |
| 086 | JavaScript ES6 | 240902T093424Z | Arnauld |
| 052 | 05AB1E | 240902T153854Z | Kevin Cr |
| 069 | Google Sheets | 240902T100442Z | doubleun |
Haskell, 128 bytes
f a b c=(g a b c,g c a b,g c b a)
g y m d=m>0&&m<13&&d>0&&d<h y m
h _ d|elem d[4,6,9,11]=31
h y 2|mod y 4<1=30
h _ 2=29
h _ _=32
Python 3, 128 117 bytes
f=lambda y,m,d:(0<m<13)*(0<d<(62648012>>2*m&3)+29or((y%4,m,d)==(0,2,29)))
g=lambda y,m,d:(f(y,m,d),f(d,y,m),f(d,m,y))
f returns 1 if y,m,d is valid, 0 if y,m,d is invalid and 1 if y,m,d is maybe valid.
C (clang), 98 bytes
i;f(*r,y,m,d){for(i=3;i--;d^=m^=d^=m)r[i]=!m|m>12|!d|d>(m-2?30|m^m>7:y%4?28:29),i>1?y^=d^=y^=d:0;}
JavaScript (Node.js) + momentjs, 76 bytes
m=require('moment')
f=(a,b,c)=>[a+b+c,c+a+b,c+b+a].map(s=>m(20+s).isValid())
Based on my Google Sheets answer. Expects three string arguments as in f('24','12','31').
Sorry no TIO, don't know how to import momentjs there. Only ran full tests in the browser + Google Apps Script (V8). The snippet below seems to work though (thanks Neil!)
m = moment
f=(a,b,c)=>[a+b+c,c+a+b,c+b+a].map(s=>m(20+s).isValid())
document.write(f('00', '01', '01') + '<br />')
document.write(f('01', '01', '31') + '<br />')
document.write(f('31', '01', '01') + '<br />')
document.write(f('01', '02', '29') + '<br />')
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js"></script>
C# (.NET 6+), 114 bytes (function) or 163 bytes (program)
var f=(string s)=>new[]{"yyMMdd","MMddyy","ddMMyy"}.Select(x=>DateTime.TryParseExact(s,x,null,0,out _)).ToList();
It takes a string as parameter and returns a list of 3 booleans corresponding to whether the string can be interpreted as {"yyMMdd", "MMddyy", "ddMMyy"}, in that order. I added ToList() because Select() returns an IEnumerable that is not computed.
The snippet makes use of the implicit using System; and using System.Linq; (since .NET 6).
Because a year on 2 digits is ambiguous, DateTime.Parse() (and similar date parsing functions) interpret it as 19xx from 50 to 99, otherwise as 20xx. Thus, for the "maybe" cases, it considers that it is for year 2000 and returns true.
Full program (163 bytes):
class P{static void Main(string[]a)=>Console.WriteLine(string.Join(',',new[]{"yyMMdd","MMddyy","ddMMyy"}.Select(x=>DateTime.TryParseExact(a[0],x,null,0,out _))));}
Try it here!
Note that due to TIO limitations (old version of C#/.NET), I added the required usings (but I didn't include them in the bytes count).
The program takes the first command line argument, and doesn't return the values but prints them to standard output instead.
JavaScript (Node.js), 79 bytes
s=>[2,6,8].map(p=>(new Date(4+[2,0,8].map(q=>s[i=(p^q)%6]+s[i+1]))+0)[8]==s[i])
Refer to Arnauld's solution for part of revision and version without Date
Arnauld's comment say pure Date won't work
JavaScript (Node.js), 88 bytes
s=>[2,6,8].map(p=>`a3${(g=q=>+s.substr((p^q)%6,2)||g)(2)%4?0:1}3232332323`[g``]>g(8)-29)
Without Date it's possibly shorter
s => (
g = q =>
+s.substr(
(p^q)%6, // magic from Arnauld
2 // XOR q=0 q=2 q=8
) || NaN, // p=2 2 0 4 If value is 0, replace
[2,6,8].map( // p=6 0 4 2 with NaN so it won't
p => // p=8 2 4 0 pass date range test
`a3${ // 0 unused, 2 decided by year
g(2)%4?0:1
}3232332323`[g(0)]
>= g(8) - 28 // Shifted by 28 to fit in string
)
Charcoal, 58 bytes
F¹⁰⁰F¹²F⎇⊖κ⁺²⁸¬﹪ι⁴⁻³¹﹪﹪κ⁷¦²⊞υ⟦ι⊕κ⊕λ⟧⭆⪪⭆”)∨^⍘”§⪪θ²Iι⁶№υI⪪ι²
Try it online! Link is to verbose version of code. Outputs three 0s or 1s depending on whether the input is in YYMMDD, MMDDYY or DDMMYY respectively. Explanation: Inspired by @KevinCruijssen's 05AB1E answer.
F¹⁰⁰
Loop over 100 years.
F¹²
Loop over 12 months (0-indexed).
F⎇⊖κ⁺²⁸¬﹪ι⁴⁻³¹﹪﹪κ⁷¦²
Loop over 28 or 29 days (February) or 31 or 30 days for the other months as appropriate.
⊞υ⟦ι⊕κ⊕λ⟧
Push a Y, M, D triplet for each valid date.
⭆⪪⭆”)∨^⍘”§⪪θ²Iι⁶№υI⪪ι²
Use the compressed string 012201210 to rearrange the input from YYMMDD, MMDDYY or DDMMYY into YYMMDD, then split each arrangement into a triplet and check whether they are in the list.
Go, 134 bytes
import."time"
func f(d string)(b[]bool){for _,F:=range[]string{"060102","010206","020106"}{_,e:=Parse(F,d);b=append(b,e==nil)}
return}
3 calls to time.Parse, with the following formats:
- 060102 for YYMMDD
- 010206 for MMDDYY
- 020106 for DDMMYY
The solution uses the fact that time.Parse returns an error if the parsing fails; checking if it's nil allows for checking if parsing succeeded.
Takes in the date as a string, and returns a slice of bools. Returns true for the maybe cases.
Retina 0.8.2, 120 bytes
(..)(..)
$'$2$1¶$'$&¶$&
%`([02468][048]|[13579][26])0229|..(?!0229|023|(0[469]|11)31)(0[1-9]|1[0-2])(?!00)([0-2].|30|31)
Try it online! Outputs three flags depending on whether the input is DDMMYY, MMDDYY or YYMMDD respectively, but link is to test suite that produces a human-readable form. Explanation:
(..)(..)
$'$2$1¶$'$&¶$&
Generate three dates, the first being YYMMDD if the input was DDMMYY, the second being YYMMDD if the input was MMDDYY, and the last being the input.
%`
Check each date separately.
([02468][048]|[13579][26])0229|..
Is this February 29th in a leap year?
(?!0229|023|(0[469]|11)31)
Disallow February 29th (in non-leap years), 30th and 31st, and also April, June, September and November 31st.
(0[1-9]|1[0-2])(?!00)([0-2].|30|31)
Check that the month is 1-12 and the day is 0-31 but not 0.
JavaScript (ES6), 86 bytes
A mix of my previous answer with @l4m2's answer.
Expects a string of 6 digits.
Returns a triplet [YYMMDD, MMDDYY, DDMMYY] of Boolean values (true for valid). Returns valid for the "maybe" cases.
s=>[2,6,8].map(p=>(new Date(4+(g=q=>s[i=(p^q)%6]+s[i+1]+" ")(2)+g``+g(8))+0)[8]==s[i])
JavaScript (ES6), 91 bytes
Without Date().
Expects a string of 6 digits.
Returns a triplet [YYMMDD, MMDDYY, DDMMYY] of binary values, with \$0\$ for valid and \$1\$ for invalid. Returns valid for the "maybe" cases.
s=>[2,6,8].map(p=>(g=q=>v=+s.substr((p^q)%6,2))``>12|!v|28+(v-2?3^~v%9&1:g(2)%4<1)<g(8)|!v)
Method
We need a short way to extract the fields at the correct positions from the input string.
We use a parameter \$p\in\{2,6,8\}\$ for the date format and a parameter \$q\in\{0,2,8\}\$ for the field type. Given \$p\$ and \$q\$, we compute the index with:
$$(p \operatorname{XOR} q)\bmod 6$$
Applying the XOR, this gives:
| XOR | \$q=0\$ (month) | \$q=2\$ (year) | \$q=8\$ (day) |
|---|---|---|---|
| \$p=2\$ | 2 | 0 | 10 |
| \$p=6\$ | 6 | 4 | 14 |
| \$p=8\$ | 8 | 10 | 0 |
And reducing modulo \$6\$, this gives:
| XOR | \$q=0\$ (month) | \$q=2\$ (year) | \$q=8\$ (day) | format |
|---|---|---|---|---|
| \$p=2\$ | 2 | 0 | 4 | YYMMDD |
| \$p=6\$ | 0 | 4 | 2 | MMDDYY |
| \$p=8\$ | 2 | 4 | 0 | DDMMYY |
Commented
s => // s = input string
[ 2, // used for YYMMDD
6, // used for MMDDYY
8 ] // used for DDMMYY
.map(p => // for each value p in the above array:
( g = q => // g is a helper function taking q:
v = +s.substr( // return the 2-digit substring extracted
(p ^ q) % 6, // from s using p and q, coerced to an integer
2 // and saved in v
) // q = 0 -> month, q = 2 -> year, q = 8 -> day
)`` > 12 // fail if the month is greater than 12
| !v // or the month is 0
| 28 + ( // compute the upper day bound:
v - 2 ? // if this is not February:
3 ^ ~v % 9 // use either 30 or 31 depending on
& 1 // the LSB of ~v % 9
: // else:
g(2) % 4 < 1 // use 29 if the year is a multiple of 4
// or 28 otherwise
) < g(8) // fail if the day is greater than the upper bound
| !v // or the day is 0
) // end of map()
05AB1E, 52 bytes
11Ýε7%É31αyΘ-LтL<ây>δšʒ`4Ör<s29QP≠]€`T‰JD2δ.IDí)JQ€à
Try it online. (No test suite, since it's too slow to run more than 2-3 test cases at once.
Explanation:
Brute-force approach to generate all valid [MM,dd,yy], [dd,MM,yy], [yy,MM,dd] dates and see if the input is in them.
Step 1a: Generate all [mm,dd,yy] dates:
11Ý # Push a list in the range [0,11]
ε # Map each value to:
7%É31αyΘ- # Calculate the amount of days in this 0-based month †:
7% # Modulo-7
É # Modulo-2 (check whether it's odd)
31α # Absolute difference with 31
y # Push the current value again
Θ # 05AB1E truthify (1 if 1; 0 otherwise)
- # Subtract that from the earlier number
L # Push a list in the range [1,daysInMonth]
тL< # Push a list in the range [0,99]
â # Cartesian product to create all [dd,yy] pairs
δ # Map over each pair:
y> š # Prepend the current value+1 (MM)
†: Taken from this answer of mine.
Step 1b: Remove all invalid [2,29,leapYear] dates:
ʒ # Filter this list of triplets by:
` # Pop and push the three values to the stack
4Ö # Check whether the year is divisible by 4
r # Reverse the stack so the month is at the top
< # Decrease it by 1 to check whether it was 2 (aka February)
s # Swap so the day is at the top
29Q # Check whether it equals 29
P # Check if all three are truthy
≠ # Invert that check
Try just steps 1a and 1b online.
Step 1c: Format all single digits to two digits with leading 0s:
] # Close both the filter and map
€` # Flatten one level down
T‰ # Divmod each inner-most value by 10
J # Then join each of those pairs back together
Step 2: Now that we have a list of all valid [MM,dd,yy]-dates, also create the other two formats:
D # Duplicate the current list
δ # Map over each inner triplet:
2 .I # Get its 0-based 2nd permutation, so [MM,dd,yy] becomes [dd,MM,yy]
D # Duplicate that list again
í # Reverse each inner triplet, so [dd,MM,yy] becomes [yy,MM,dd]
) # Wrap all three lists of triplets on the stack into a list
Try the first two steps online, with added footer to have ten random dates from each format.
Step 3: Verify in which of the three lists of date-formats the input-string is:
J # Join each inner triplet together to a string of six digits
Q # Check for each of those whether it equals the (implicit) input
€ # Map over each inner list of checks:
à # Check of any is truthy by leaving the maximum
# (after which the resulting triplet is output implicitly)
Google Sheets, 69 bytes
=bycol({A3,C3,C3;B3,A3,B3;C3,B3,A3},lambda(_,isdate(20&join("-",_))))
Put the three date components in cells A3:C3 as in 24, 12, 31 and the formula in cell H3.

The formula lists the components in a matrix with the combinations listed in the question down each of three columns, iterates those columns to get each combo as yyyy-MM-dd, and determines whether it is a valid date.
Years like 2000 and 2400 are leap years, but years like 1800, 1900 and 2100 aren't. A string like 000229 would therefore be indeterminate in the yyMMdd format, because we don't know whether it refers to 1900, 2000 or some other year. To show maybe with these strings, use this (99 bytes):
=bycol({A3,C3,C3;B3,A3,B3;C3,B3,A3},lambda(_,if(join(,_)="000229","maybe",isdate(20&join("-",_)))))
Ungolfed:
=bycol(
{
A3, C3, C3;
B3, A3, B3;
C3, B3, A3
},
lambda(col,
if(join("", col) = "000229", "maybe", isdate(20 & join("-", col)))
)
)