g | x | w | all
Bytes Lang Time Link
128Haskell241021T213017ZDPD-
117Python 3240903T025930ZLucenapo
098C clang240909T194805Zjdt
076JavaScript Node.js + momentjs240903T101110Zdoubleun
nanC# .NET 6+240904T120218ZArkane
079JavaScript Node.js240902T084009Zl4m2
058Charcoal240903T222310ZNeil
134Go240903T191837Zbigyihsu
120Retina 0.8.2240903T175255ZNeil
nanRuby240903T084423ZG B
086JavaScript ES6240902T093424ZArnauld
05205AB1E240902T153854ZKevin Cr
069Google Sheets240902T100442Zdoubleun

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

Try it online!

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

Try it online!

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

Try it online!

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

Try it online!

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)

Try it online!

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
)

Modifying Arnauld's also result 88, with maybe be false

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}

Attempt This Online!

3 calls to time.Parse, with the following formats:

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.

Ruby, 71 61+4=65 bytes

->a,b,c{[a+b+c,c+a+b,c+b+a].map{|x|!!Date.parse(x)rescue !0}}

Try it online!

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

Try it online!


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)

Try it online!

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.

Try just step 1a online.

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

Try just step 1 online.

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.

screenshot

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