24
\$\begingroup\$

Task

A date can be compactly represented in a 6-character string in the format ddmmyy where the first two characters (dd) represent a day, the 3rd and 4th characters (mm) represent a month and the last two characters (yy) represent a 20XX year. Given a string with 6 characters in [0-9] determine if it represents a valid date. But because today (the day this was posted) is April Fools' day, we will have a twist in the way dates work:

April Fools' dates

We will pretend every 30-day month has 31 days and every 31-day month has 30 days. Furthermore, in years when February is supposed to have 29 days we will pretend February only has 28 days and in all the other years we will pretend February has 29 days; i.e.:

  • months 01, 03, 05, 07, 08, 10 and 12 have 30 days;
  • months 04, 06, 09 and 11 have 31 days;
  • February has 28 days if the year yy is a multiple of 4, otherwise February has 29 days (let us assume we are in the year 20yy);

Input

An integer in [0 - 311299] or a 0-padded string representation of such an integer.

Output

A Truthy value if the input corresponds to a date as per the April Fools' dates, Falsy otherwise.

Test cases

Python naïve implementation for your convenience.

"000511" -> False
"000611" -> False
"290200" -> False
"290204" -> False
"290208" -> False
"310004" -> False
"310005" -> False
"310104" -> False
"310105" -> False
"310204" -> False
"310205" -> False
"310304" -> False
"310305" -> False
"310504" -> False
"310505" -> False
"310704" -> False
"310705" -> False
"310804" -> False
"310805" -> False
"311004" -> False
"311005" -> False
"311204" -> False
"311205" -> False
"311304" -> False
"311305" -> False
"311404" -> False
"311405" -> False
"010694" -> True
"031288" -> True
"050199" -> True
"050298" -> True
"050397" -> True
"060496" -> True
"070595" -> True
"100793" -> True
"150892" -> True
"181189" -> True
"200991" -> True
"251090" -> True
"280200" -> True
"280201" -> True
"280202" -> True
"280203" -> True
"280204" -> True
"280205" -> True
"280206" -> True
"280207" -> True
"280208" -> True
"290201" -> True
"290202" -> True
"290203" -> True
"290205" -> True
"290206" -> True
"290207" -> True
"310404" -> True
"310405" -> True
"310604" -> True
"310605" -> True
"310904" -> True
"310905" -> True
"311104" -> True
"311105" -> True

This challenge was inspired by this one.


This is so shortest submission in bytes, wins! If you liked this challenge, consider upvoting it! If you dislike this challenge, please give me your feedback. Happy golfing!

\$\endgroup\$
  • 1
    \$\begingroup\$ This will probably also discourage using built-ins \$\endgroup\$ – Redwolf Programs Apr 1 at 15:58
  • \$\begingroup\$ @RedwolfPrograms do you mean that as a plain statement, a pro of this challenge or a con? \$\endgroup\$ – RGS Apr 1 at 16:00
  • 8
    \$\begingroup\$ A definite pro. Should encourage a lot of interesting answers. \$\endgroup\$ – Redwolf Programs Apr 1 at 16:01
  • 1
    \$\begingroup\$ Should include a test case where the day is 0. \$\endgroup\$ – Xcali Apr 1 at 18:28
  • \$\begingroup\$ Are we allowed to take the input as day/month/year? \$\endgroup\$ – S.S. Anne Apr 1 at 19:43

13 Answers 13

15
\$\begingroup\$

JavaScript (ES6),  62 60  59 bytes

Takes input as a 0-padded string. Returns \$0\$ for false or a positive integer for true.

s=>(m=s[2]+s[3])<13&31-(m^2?~m%9%2:s%4?1:2)>(s/=1e4)&&~~s*m

Try it online!

or Check all possible outputs against an ungolfed implementation

Commented

s =>                // s = input string
  (m = s[2] + s[3]) // m = month, as a string
  < 13 &            // make sure that m is less than 13
  31 - (            // compute the upper bound for this month:
    m ^ 2 ?         //   if the month is not February:
      ~m % 9 % 2    //     use either 31 or 32
    :               //   else:
      s % 4 ?       //     if this is not a leap year:
        1           //       use 30
      :             //     else:
        2           //       use 29
  )                 // end of upper bound computation
  > (s /= 1e4)      // make sure that it's greater than the day
  && ~~s * m        // and finally make sure that day * month is not zero
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Simply brilliant. I especially love the ~m%9%2. For my own solution I tried regular expressions but soon realised I wouldn't get it anywhere near 100 chars, let alone your sixty-something... \$\endgroup\$ – Christallkeks Apr 2 at 23:28
  • \$\begingroup\$ @Christallkeks Thank you. :-) Note that a direct port of Neil's 100% regex answer would be 94 bytes. \$\endgroup\$ – Arnauld Apr 3 at 9:21
  • \$\begingroup\$ longer than hardcode \$\endgroup\$ – l4m2 Apr 22 at 9:26
7
\$\begingroup\$

Python 3.8, 77 67 65 62 61 bytes

-2 bytes thanks to @Bubbler
-3 bytes thanks to @xnor
-1 byte thanks to @PoonLevi's mod by float trick

lambda s:13>(m:=s//100%100)>0<s//1e4<30-[s%4<1,m%-1.76][m!=2]

Try it online!

Input: Date as an integer.
Output: True or False if the date is valid or invalid respectively.

How:

Overall approach: return 13 > m > 0 < d < max_date_of_month where d, m are date and month respectively.
The max date of month m is calculated as:

  • If m==2: 30-(s%4<1) evaluates to 29 if the year is divisible by 4, and 30 otherwise. Since the year is the last 2 digits of the input, input mod 4 is the same as the year mod 4.
  • If m!=2: 30-m%-1.76 evaluates to 31.xxx or 30.xxx

Old solution

Python 3.8, 86 83 71 bytes

lambda s:13>(m:=s//100%100)>0<s//1e4<29+[s%4>0,([3,2]*7)[m+m//8]][m!=2]

Try it online!

Input: Date as an integer.
Output: True or False if the date is valid or invalid respectively.

How: ([3,2]*7)[m+m//8] first creates a list storing the max_date + 1 for each month (except February) by repeating [3, 2] a few times. If the month is August or after, the pattern switches, so we add 1 to the index.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ -2 bytes. \$\endgroup\$ – Bubbler Apr 2 at 2:07
  • \$\begingroup\$ @Bubbler thanks! \$\endgroup\$ – Surculose Sputum Apr 2 at 4:07
  • 1
    \$\begingroup\$ 29+[s%4>0,2+m%-7%2][m!=2] saves 3 bytes \$\endgroup\$ – xnor Apr 2 at 4:07
  • \$\begingroup\$ @xnor Very nice way to get rid of those brackets! \$\endgroup\$ – Surculose Sputum Apr 2 at 4:14
  • 1
    \$\begingroup\$ -1: 30-[s%4<1,m%-1.76][m!=2]. The divisor must be somewhere between -7/4 and -9/5 (exclusive) for it to switch between 7 and 8. \$\endgroup\$ – Tipping Octopus Apr 2 at 20:37
5
\$\begingroup\$

Retina 0.8.2, 96 93 91 81 bytes

^(?!(..)?00|..[2-9]|..1[3-9]|31(?!0[469]|11)|3002|2902([02468][048]|[13579][26]))

Try it online! Link includes test cases. Edit: Saved 3 bytes thanks to @mathjunkie. Saved 2 bytes thanks to @ThomasAyoub. Saved a further 10 bytes thanks to @ThomasAyoub for noting that the day cannot be greater than 31. Explanation:

^

Match only at the beginning of the string.

(?!...)

Invert the condition so we're now looking for invalid dates. The invalidity conditions (separated by | in the original code) are as follows:

(..)?00

Either the day or month are zero.

..[2-9]

The month is 20 or higher.

..1[3-9]

The month is between 13 and 19.

31(?!0[469]|11)

The day is 31 and the month is not 4, 6, 9 or 11.

3002

February 30th.

2902([02468][048]|[13579][26])

February 29th on a leap year.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ 93 bytes: Try it online! \$\endgroup\$ – math junkie Apr 1 at 21:34
  • \$\begingroup\$ (?!04|06|09|11) could be (?!0[469]|11) to save 2 bytes \$\endgroup\$ – Thomas Ayoub Apr 2 at 12:13
  • \$\begingroup\$ Since input is limited to 311299, you can save bytes again removing [4-9]| \$\endgroup\$ – Thomas Ayoub Apr 2 at 12:23
  • \$\begingroup\$ same goes for (3|..)[2-9] \$\endgroup\$ – Thomas Ayoub Apr 2 at 12:27
  • \$\begingroup\$ @ThomasAyoub Ah, I hadn't realised that. I guess it's only the day to which that restriction applies, right? \$\endgroup\$ – Neil Apr 2 at 12:28
4
\$\begingroup\$

Jelly, 28 bytes

Ɠ⁽¿ÇB31_+2¦4ḍ~ƊR;€"J$ḅ³Fċ:³$

A full program accepting a single integer from STDIN which prints a 1 or 0 to STDOUT.

Try it online! Or see the test-suite.

How?

Ɠ⁽¿ÇB31_+2¦4ḍ~ƊR;€"J$ḅ³Fċ:³$ - Main Link
Ɠ                            - set the chain's left argument, N, to evaluated STDIN
 ⁽¿Ç                         - base 250 integer = 3765
    B                        - to binary     = [1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1]
     31_                     - 31 minus      = [30,30,30,31,30,31,30,30,31,30,31,30]
              Ɗ              - last three links as a monad - f(N):
           4ḍ                -   four divides (N)?
             ~               -   bitwise NOT (0 becomes -1 and 1 becomes -2)
          ¦                  - sparse application...
         2                   - ...to indices: [2]
        +                    - ...action: add
                               i.e. x=9 or 8: [30,2x,30,31,30,31,30,30,31,30,31,30]
               R             - range (vectorises) = [[1,2,...30],...]
                    $        - last two links as a monad - f(that):
                   J         -   range of length = [1,2,...,12]
                  "          -   zip with:
                ;€           -     concatenate each -> [[[1,1],[2,1],...,[30,1]],...]
                     ḅ       - convert from base (vectroises):
                      ³      -   100               -> [[101,201,...,3001],...]
                       F     - flatten
                        ċ    - count occurrences of:
                           $ -   last two links as a monad - f(N):
                         :   -     (N) integer divide:
                          ³  -       100
| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

05AB1E, 34 bytes

2ô¨Ðθ©13‹sĀPr`2QiI4Ö≠ë®7(%ÉÌ}29+‹P

Just an initial answer. Can definitely be golfed by a few bytes.
Inspired by both @Arnauld's JavaScript answer and @SurculoseSputum's Python answer, so make sure to upvote them!!

Try it online or verify all test cases.

Explanation:

2ô             # Split the (implicit) input in parts of size 2: ddmmyy → [dd,mm,yy]
  ¨            # Remove the last item (the year): [dd,mm]
   Ð           # Triplicate this
               #  STACK: [[dd,mm],[dd,mm],[dd,mm]]
    θ          # Pop and push the last item
               #  STACK: [[dd,mm],[dd,mm],mm]
     ©         # Store the month in variable `®` (without popping)
      13‹      # Check that it's smaller than 13
               #  STACK: [[dd,mm],[dd,mm],mm<13]
   s           # Swap to get the triplicate value again
               #  STACK: [[dd,mm],mm<13,[dd,mm]]
    ĀP         # Check for both that they're not 0
               #  STACK: [[dd,mm],mm<13,(dd!=0)*(mm!=0)]
   r           # Reverse the stack
               #  STACK: [(dd>0)*(mm>0),mm<13,[dd,mm]]
    `          # Push both values separately to the stack
               #  STACK: [(dd>0)*(mm>0),mm<13,dd,mm]
     2Qi       # If the month is 2:
        I4Ö≠   #  Check that the input is NOT divisible by 4
               #   STACK: [(dd>0)*(mm>0),mm<13,dd,input%4>0]
       ë       # Else:
        ®7(%É  #  Check that the month (from variable `®`) modulo -7 is odd
               #   STACK: [(dd>0)*(mm>0),mm<13,dd,mm%-7%2>0]
             Ì #  And increase this by 2
               #   STACK: [(dd>0)*(mm>0),mm<13,dd,(mm%-7%2>0)+2]
       }29+    # After the if-else: add 29 to this value
               #  STACK: [(dd>0)*(mm>0),mm<13,dd,(input%4>0)+29] if mm == 2
               #  STACK: [(dd>0)*(mm>0),mm<13,dd,(mm%-7%2>0)+31] if mm != 2
           ‹   # Check that the dd is smaller than this value
               #  STACK: [(dd>0)*(mm>0),mm<13,dd<(input%4>0)+29] if mm == 2
               #  STACK: [(dd>0)*(mm>0),mm<13,dd<(mm%-7%2>0)+31] if mm != 2
            P  # And take the product of the stack to check if all are truthy
               #  STACK: [(dd>0)*(mm>0)*(mm<13)*(dd<(input%4>0)+29)] if mm == 2
               #  STACK: [(dd>0)*(mm>0)*(mm<13)*(dd<(mm%-7%2>0)+31)] if mm != 2
               # (after which this is output implicitly as result)
| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Python 3.8, 136 \$\cdots\$93 78 bytes

Takes the date as an integer and returns Truthy or Falsy.

lambda s,h=100:13>(m:=s//h%h)>0<s//h//h<(30-(s%4<1),31+(m in(4,6,9,11)))[m!=2]

Try it online!

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Perl 5 Mbigint -p, 76 75 bytes

/(..)(..)/;$_=$1>0&&$1<substr 113130-($_%4?0:1).31323132313132313231,2*$2,2

Try it online!

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Java (JDK), 74 bytes

n->{int m=n/100%100;return(m==2?n%4<1?2:1:~m%9%2)<31-(n/=1e4)&13>m&n*m>0;}

Try it online!

Credits

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

C (gcc), 95 \$\cdots\$ 71 65 bytes

Saved 3 4 bytes thanks to ceilingcat!!!
Saved a whopping 15 bytes thanks to Olivier Grégoire!!!
Saved 6 bytes thanks to Arnauld!!!

Takes the date as an integer and returns \$0\$ or \$1\$.

m;f(s){m=s/100%100;s=m<13&(m-2?~m%9%2-1:s%4<1)+(s/=1e4)<30&&s*m;}

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Replace (m-4&&m-6&&m-9&&m-11)-2 with ~m%9%2-1. \$\endgroup\$ – Olivier Grégoire Apr 2 at 12:24
  • \$\begingroup\$ @OlivierGrégoire Fantastic - thanks! :-) \$\endgroup\$ – Noodle9 Apr 2 at 13:05
  • \$\begingroup\$ 65 bytes, I think -- but this should be double-checked. \$\endgroup\$ – Arnauld Apr 3 at 10:46
  • \$\begingroup\$ @Arnauld Looks good. Very nice - thanks! :-) \$\endgroup\$ – Noodle9 Apr 3 at 11:04
2
\$\begingroup\$

Bash + GNU utilities, 86 85 83 82 bytes

a=0424343443434;fold -2|xargs|(read d m y;date -d${a:${m#0}:1}/$d/0$[!(${y#0}%4)])

Try it online!

Input is on stdin.

Output is the exit code: 0 for truthy, 1 for falsey.


I thought I'd do a solution based on a date built-in, since I don't think anyone else has done that yet.

This program takes the input string \$x\$ and computes another string \$y\$ with the property that \$x\$ is a valid "April Fools date" iff \$y\$ is a valid normal date. So GNU date applied to \$y\$ will give the desired answer.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Swift 279 277 272 264 262 257 256 254 252 bytes

func v(s:String)->Int{let m=Int(s.suffix(4).prefix(2))!;switch m{case 0,13...:return 0;case _:switch Int(s.prefix(2))!{case 1...28:return 1;case 29,30:return Int(s.suffix(4))!%4==0&&m==2 ?0:1;case 31:return[4,6,9,11].contains(m) ?1:0;case _:return 0}}}

My first and most probably failed attempt at code golf. Please be nice!

Here is a more readable version:

func validDate(s :String) -> Int {
    let mm = Int(s.suffix(4).prefix(2))!
    switch mm {
    case 0,13...:
        return 0
    case _:
    switch Int(s.prefix(2))! {
    case 1...28:
        return 1
    case 29, 30:
        return Int(s.suffix(4))! % 4 == 0 && mm == 2 ? 0: 1
    case 31:
        return[4,6,9,11].contains(mm) ? 1:0
    case _:
        return 0
    }
  }
}

Any constructive feedback is welcome, negative feedback not so welcome.

Link to project with swift tests on Github

Updated solution to make it work for console input

288 251 249 bytes

let s=readLine()!;let m=Int(s.suffix(4).prefix(2))!;let d=Int(s.prefix(2))!;if m<0||m>13{print(0)};if(1...28).contains(d){print(1)}else if d==29||d==30{print(!(Int(s.suffix(4))!%4==0&&m==2))}else if d==31{print([4,6,9,11].contains(m))}else{print(0)}

Try it online

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Hey there, welcome! Can you provide any sort of [try it online link](https:tio.run) ao we can run your answer? :) \$\endgroup\$ – RGS Apr 4 at 20:42
  • \$\begingroup\$ Hi, I'm not sure how they work. Here is a link to my repo for this challenge which contains all the pythons tests provided converted to swift. Downloading it, installing swift and running swift test in the directory should run the tests on Mac or Linux. github.com/johannwerner/AprilFoolsGolfChallenge \$\endgroup\$ – user1898829 Apr 5 at 8:20
  • \$\begingroup\$ The way they work is simple. You go to this TIO Swift link, paste your code and tests, and then use the hyperlink button on top of the page to generate a link that points to the code you just pasted. For example, here is a link to a python program that prints "hey there, user1898829". \$\endgroup\$ – RGS Apr 5 at 8:27
2
\$\begingroup\$

JavaScript (Node.js), 53 bytes

s=>`2${s&3&&1}2323223232`[s[2]+s[3]-1]>s/1e4-29&s>1e4

Try it online!

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Raku (raku -n file-with-one-line) 118 Bytes

/(..)(.)(.)(..)/;$!=10*$1+$2;die if 12 <$!||1>$!;$!=7.5-abs(7.5-$!);$!=($!+|4)+^1 if $!!= 2;Date.new($3%4??0!!1,$!,$0)

Result as exit code (0: ok, 1: error)

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.