You know what a palindrome, a prime and a date are.

Your task is to list all dates in 100 thousands of years that fulfill all three characteristics.

Nevermind anything but the numbers, use the following formats: YYYYMMDD and YYYYYMMDD.

Dates between 0000-01-01 and 9999-12-31 should be printed as 8 digit palindromes dates (If there is any?) and dates between 10000-01-01 and 99999-12-31 should be printed as 9 digit palindromes.

It's not mandatory to list the dates in chronological order.

Example part of valid output.

First three 9 digit prime palindromic dates:



Standard loopholes apply.


13 Answers 13


Ruby, 144 141 bytes (134+7 for the -rprime flag)

Saved 3 bytes thanks to benj2240!

Time.new(y,m,d).day==d.to_i&&r.to_i.prime?&&(p r)}}}

Try it online!

The algorithm:

  • generate all possible MMDD combinations, from "0101" to "1231"
  • generate all years for that date that would result in a palindrome, by reversing the MMDD string and adding in the middle, in turn, all chars in the (0..9) range
  • check if that is a valid date by creating a Time instance with the given y, m, d values. If the resulting time object has a #day value equal to d, then that was a valid date. Otherwise, it would shift the date (for example, Time.new 2018,2,30 returns 2018-03-02).
  • check if the valid palindrome date is also a prime and display it if it is.

The inner loop was initially a function that was called for each element in the (?0..?9) range, as well as for the empty string.

Since the empty string produced no results (there are no valid 8 digit prime palindromes), I decided to remove it and refactor to this version.

  • \$\begingroup\$ I think you can save a few bytes by removing the t variable: TIO \$\endgroup\$
    – benj2240
    Commented Feb 10, 2018 at 0:26
  • \$\begingroup\$ @benj2240 That's right! Thanks! \$\endgroup\$ Commented Feb 10, 2018 at 8:04

Python 2, 116 107 128 122 119 bytes

def g(n=9**8):
 while n<1e9:
  if 0<m<13and n%100<31+(m+m/8)%2and`n`[::-1]==`n`and 2**n%n==2:print n

The second half of the 4th line is inspired by mxdsp's answer here to another golf question.


The function g() takes an argument only to initialize the n variable using its default value. The initial value is an odd number that's as short as possible and as large as possible while still being less than the first valid answer 100111001.

Loop until n reaches the end of the date range 109. Increment n by 2. m is the month of date n.

If n is a valid date, palindrome and prime, print it:

  • Date:
    • 0 < m < 13 checks that m is a valid month.
    • n % 100 < 31 + (m+m/8)%2 checks that n's day of the month is valid. (m+m/8)%2 adds 1 for all months with 31 days. Credit for that goes to ArmanX's answer. There are no primes for February 29-30.
  • Palindrome: `n`[::-1] == `n`. The backticks stringify n. [::-1] reverses the string.
  • Prime: 2**n % n == 2 is a Fermat primality test. That test is only probabilistic. There are also non-primes that match. But not in the range of numbers we're looking at.
  • \$\begingroup\$ Nice one using the Fermat’s primality test! \$\endgroup\$
    – agtoever
    Commented Feb 10, 2018 at 8:51

APL (Dyalog Unicode), 155 bytes

:If n≡⌽n
:AndIf 1 pco x
:AndIf m<13
:AndIf d<32
:If m d≡2 29
:AndIf (400|⍎((≢n)-4)↑n)=0
f x+72
f x+1

Try it online!

This is a Tradfn (traditional function) that takes one argument arg = yyyymmdd or arg = yyyyymmdd. Usage is f arg.

This will not output anything when the argument starts at 10000101 because it doesn't find a prime palindrome date in 60 seconds.

Here is a less golfed approach that will output the OP's example output of


(Try it Online!)

Notice that both codes are the exact same until right before calling the function recursively for the next date. While the golfed version just calls it as f arg+1, the less golfed code jumps from day 31 to day 01 and from month 12 to month 01, which speeds it up quite a bit.

How it works:

⎕CY'dfns'                   ⍝ Copy (⎕CY) all dfns to enable the use of pco.
n←⍕x                        ⍝ Assign (←) the input to the variable n.
m←(⍎2↑¯4↑n)                 ⍝ Take (↑) the last 4 (¯4) elements of n, then take the first 2 elements of that and assign to m. 
d←(⍎¯2↑n)                   ⍝ Take the last 2 (¯2) elements of n, and assign to d.
:If n≡⌽n                    ⍝ If n matches (≡) its reverse (⌽) (is a palindrome)
:AndIf 1 pco x              ⍝ And a prime (1 pco)
:AndIf m<13                 ⍝ And month < 13
:AndIf d<32                 ⍝ And day < 32
:If m d≡2 29                ⍝ If it is 2/29
:AndIf (400|⍎((≢n)-4)↑n)=0  ⍝ And the year mod 400 = 0
⎕←x                         ⍝ Print x
f x+72                      ⍝ call f with arg year0301
⎕←x                         ⍝ Print x
f x+1                       ⍝ call f for the next date.

Python 3, 163 bytes

for m in r(1,13):
 for d in r(1,31+(m%2==(m<8))-2*(m==2)):
  for i in r(10):x=int(t[::-1]+str(i)+t);all(x%i for i in r(2,x))and print(x)

Solution is fairly long (and probably can get improved upon), but doesn't use any built-in functions for prime/date/palindrome checking. A somewhat ungolfed version for clarity:

for month in range(1,13):
    for day in range(1,31 + (month%2==(month<8)) - 2*(month==2)):
        t = "%02d%02d" % (month, day)
        for i in range(10):
            x = int(t[::-1] + str(i) + t)
            if all(x%i for i in range(2,x)):print(x)

Valid dates are generated by choosing a month and day. As commented before, only size 9 need be considered. Also note that leap years aren't considered. This isn't required because of the lucky coincidence that palindrome primes of length 9 which end on 0229 simply don't exist (other date anomalies like the 30th February of 1712 can be discarded for the same reason).

Next the middle digit is chosen freely, and a prime test is performed. Because of the prime test had to be as short as possible, it is very naive and thus cripplingly slow. Using an external library could solve this (and save some bytes), but as mentioned before I didn't want to use any.

  • \$\begingroup\$ You should make your code look exactly how it does when you counted bytes (in this case by collapsing indent spacing). Also, it's great that you included an ungolfed version, but usually the golf version is listed first \$\endgroup\$
    – wnnmaw
    Commented Jan 15, 2018 at 19:28
  • \$\begingroup\$ @wnnmaw The only difference between the version I counted on the one supplied in the answer, is I used tabs instead of the spaces that get used here. As I'm aware tabs get auto-converted, so I don't see any way to fix this. \$\endgroup\$
    – Def
    Commented Jan 15, 2018 at 19:36
  • \$\begingroup\$ @Def IIRC Python allows you to use spaces as indentations too, that way it could look the same in your answer too. Correct me if I'm wrong on the first part though. \$\endgroup\$ Commented Jan 15, 2018 at 19:43
  • \$\begingroup\$ @elementbound It does indeed, thanks for the suggestion. \$\endgroup\$
    – Def
    Commented Jan 15, 2018 at 19:49

WolframLanguage (Mathematica) 187 bytes

There may be some reduction in size to be found. Explanation to follow...

t=ToString;p=PadLeft;d=DateObject;Cases[""<>{t/@p[#,If[Length@#<5,4, 5]],t/@ p[#2,2],t/@p[#3,2]}&@@@(IntegerDigits/@#[[1]]&/@DayRange[d@#,d@#2]),x_/;PalindromeQ@x&&PrimeQ@ToExpression@x]&

Test cases

t = ToString; p = PadLeft; d = DateObject;
Cases["" <> {t /@ p[#, If[Length@# < 5, 4, 5]], t /@ p[#2, 2], 
   t /@ p[#3, 2]} & @@@ (IntegerDigits /@ #[[1]] & /@ DayRange[d@#, d@#2]), 
   x_ /; PalindromeQ@x && PrimeQ@ToExpression@x] &[{10011, 10, 1}, {10017, 1, 1}]

(* {"100111001", "100131001", "100161001"} *)

Explanation of code

DayRange[d@#,d@#2] returns all of the dates between {10011, 10, 1}and {10017, 1, 1}. In this case, it returns approximately 5 years, 4 months of dates (precisely 1920 dates). Leap years are taken into account.

The dates are returned in Wolfram-standard formatting. For example, the first date will appear as DateObject[List[1,1,1],"Day","Gregorian",-5.]`

#[[1]] & /@ will remove the part of the date, in each date, that concerns us. In the example, DateObject[List[1,3,7],"Day","Gregorian",-5.] returns the abbreviated date, {1,3,7}.

t/@p[#3,2]} or ToString/@Padleft[#3,2] pads the third element, namely, the 7 standing "for 7th day of the month" as "07". Similar padding is provided for the single digit symbol for the month of March, namely, 3 is returned as "03".

p[#, If[Length@# < 5, 4, 5]] pads the year with zeros to reach the length of a 4 or 5 digit string. In this case, January, namely 1, is returned as `"00001"'.

"" <>... joins the strings. In this case, it returns "000010307".

Cases[...x_ /; PalindromeQ@x && PrimeQ@ToExpression@x] returns those cases, among the 1920 dates, that are palindromes and primes.


Javascript, 187 177

Assumptions: no matching 4 digit years; no matching days in February between 29-30


It works like this:

p=n=>(n<10?'0':'')+n;       //Prepend a 0 for 1-digit numbers and convert to a string
f=n=>n[3]+n[2]+n[1]+n[0];   //Flip four digits
for(m=13;--m;)              //Month loop, from 12 to 1
       31+(m+(0|m/8))%2     //Calculate the days in the month, allowing  Feb. 29 & 30
                       ;--d;){ //Day loop
  for(y=10;y--;){           //Middle digit loop
   z=p(m)+p(d);             //Prepend zeros to the month and day
   Y=+(f(z)+y+z);           //Flip the digits; append the middle digit,
                            //month, and day; convert back to an integer
   for(i=2;Y%i&&i*i<Y;i++); //Check if it's a prime
    if(Y%i)console.log(Y)}} //If it doesn't divide evenly, it's not prime. Print it!


  • 187 to 177: There are no prime palindrome dates that fall on Feb. 29 or 30, so we can pretend Feb. has 30 days and save 10 characters.


Through testing, I found there are no valid matches that are 4-digit years or fall on Feb. 29 or 30. There are, unfortunately for the sake of the code, exactly five (invalid) results that fall on the 31st of various months that only have 31 days.


Java 10, 329 327 320 318 312 308 307 264 bytes

v->{for(int y=9999,m,d;++y<1e5;)for(m=0;++m<13;)for(d=0;++d<32;)try{java.time.LocalDate.of(y,m,d);var t=y+"".format("%02d%02d",m,d);long n=new Long(t),x=1;for(;n%++x%n>0;);if(t.contains(new StringBuffer(t).reverse())&n==x)System.out.println(t);}finally{continue;}}

-1 byte thanks to @assylias.


Try it online (note: the prime-checking part has been replaced with a more efficient separated method, although even with that it still times out after 60 seconds, only outputting the first ~115 palindromic prime dates).
Pastebin of all 197 outputs from a local run.

v->{                           // Method without empty unused parameter and no return-type
  for(int y=9999,m,d;++y<1e5;) //  Loop over the years in the range [1000,9999]:
    for(m=0;++m<13;)           //   Inner loop over the months in the range [1,12]:
      for(d=0;++d<32;){        //    Inner loop over the days in the range [1,31]:
                               //     If it's a valid date:
          var t=y+"".format("%02d%02d",m,d);
                               //      Convert the numbers to a String in format "yyyyyMMdd"
          long n=new Long(t),  //      Convert this String to a long
          x=1;for(;n%++x%n>0;);//      Prime-checking loop
          if(t.contains(new StringBuffer(t).reverse())
                               //      If the string is palindromic
             &n==x)            //      and the long is a prime:
                               //       Print the string with trailing newline
        }finally{              //     If it isn't a valid date:
          continue;}}}         //      Continue to the next iteration of the inner-most loop
  • 1
    \$\begingroup\$ if(t.equals(new StringBuffer(t).reverse()+"") -> if(t.contains(new StringBuffer(t).reverse()) to save 1 character (works because we know both strings have the same length). That's not much :-( \$\endgroup\$
    – assylias
    Commented Jan 17, 2018 at 15:25
  • \$\begingroup\$ @assylias Smart, I like it. Thanks! And although 1 byte is not much, it's still 1 byte. Codegolf is always about making it as short as possible, so every byte counts. :) \$\endgroup\$ Commented Jan 17, 2018 at 15:31

VBA, 347

Sub PalindromeDate()
Dim DateString As String
For i = 0 To 9999
    For j = 1 To 12
        For k = 1 To 31
        DateString = Format(i, "0000") & Format(j, "00") & Format(k, "00")
        If DateString = StrReverse(DateString) Then
        Debug.Print DateString
        End If
        Next k
        Next j
        Next i

End Sub
  • \$\begingroup\$ Welcome to PPCG! I don't know VBA, but it looks like you could golf some whitespace off. \$\endgroup\$
    – qqq
    Commented Jan 15, 2018 at 21:37
  • \$\begingroup\$ I also don't really know VBA, but I think DateString is an arbitrary variable name, so you should be able to reduce that to a single character, right? \$\endgroup\$ Commented Jan 15, 2018 at 22:23
  • 3
    \$\begingroup\$ And I think you missed the prime part of "palindromic prime dates". \$\endgroup\$
    – mercator
    Commented Jan 15, 2018 at 23:09
  • \$\begingroup\$ There would be some code for calculate leap years (the one has February 29 days) \$\endgroup\$
    – user58988
    Commented Jan 16, 2018 at 17:51
  • \$\begingroup\$ 5-digit years are also missing, and Else is not necessary. \$\endgroup\$ Commented Feb 10, 2018 at 10:42

Deadfish~, 10529 bytes


Clean, 262... 213 bytes

import StdEnv
@ =(rem)
f=[d\\d<-[a*10^4+b*100+c\\a<-[10^4..99999],b<-[1..12],c<-[1..28+[0,3,if(@a 400<1|| @a 4<1&& @a 100>0)1 0,3,2,3,2,3,3,2,3,2,3]!!b]]|(\k=k==reverse k)[p\\p<-:toString d]&&all((<)0o@d)[2..d-1]]

Try it online!


Javascript, 234 229 bytes

A bit bulky, but posting it to get the JS ball rolling. Any suggestions welcome!

p=n=>{for(i=2;i<n;n=n%i++<1?0:n);return n>1}


// Flip a one- or two-digit number

// Primality test
// For initial testing, you can replace this line with:
//      p=require('primality')
// This uses the primality npm module and is way faster
p=n=>{for(i=2;i<n;n=n%i++<1?0:n);return n>1}

// Convert number to string, pad with zeroes if necessary

    // Loop months
        // Loop days
            // Loop middle digit
            for(x=10;--x+1;) {
                // Construct 'date'
                s = 
                    // Start with day and month, each flipped
                    q(f(d))+q(f(m)) + 
                    // Add middle digit ( will be casted to string since the previous expression is also a string)
                    x + 
                    // Add month and date as they are

                    // Check for primality
                    p(s|0) && 
                    // Check if it's a valid date by validating day ( month and year will always be valid)
                        // For February, we always assume 28 days ( check for 29 because we use less than)
                        m==2?29 : 
                        // For other months, it alternates between 31 and 30
                        // EXCEPT July and August both have 31 days, then continues alternating

How it works:

The digit flipping magic is based mostly on experimenting.
I started by figuring out what number to subtract from to get the flipped version. I only cared about the last two digits.
So, if we take n, find k so that n+k=flip(n). For 10<n<20 k started at 101 and increased in increments of 9. However, for n<10, this was 100. I assumed k increased for every jump of 10, and after a bit of fiddling I figured it was correct.
So, k=100+9*n+n//10 where // means integer division.

Thus, we get n+k = n+(100+9*n+n//10) = 100+10*n+n//10 = flipped(n).

I cannot prove, nor claim that this works for any number, but it produced correct results for the numbers used here.

For the primality test, credit to Kevin Cruijssen's answer. I had a bit shorter version, but I could not get it right:

p=n=>{for(i=n;--i-1;)if(!(n%i))return 1;}

I skipped on the palindrome test, by looping over months, days and a middle digit so I can build strings as dDmMxMmDd, where D is the day's first digit, d is the second, etc.


Saved 5 bytes by getting rid of the conditional part of q

q=n=>n<10?'0'+n:(''+n).slice(-2) // from
q=n=>(''+(100+n)).slice(-2)      // to
  • \$\begingroup\$ Sorry for messing around with the byte counts. Slipped in some soft-tabs accidentally. Should be correct now. \$\endgroup\$ Commented Jan 16, 2018 at 11:31
  • \$\begingroup\$ You're only ever using f's result as a parameter to q, so cut out the middle man and write f=n=>''+n%10+(n/10|0), and q's result is always used as a string, so you can write q=n=>n<10?'0'+n:n. \$\endgroup\$
    – Neil
    Commented Jan 17, 2018 at 9:58

APL NARS 626 bytes, 313 chars

x←2 12⍴v,v←31 28 31 30 31 30 31 31 30 31 30 31
X:  i←{(0=4∣⍵)∧0≠100∣⍵:1⋄0=400∣⍵:1⋄0}y
A:  →0×⍳y≥1e5
B:  d+←1
C:  m+←1⋄→A

this print what find in 50 second, than stop itself (because otherwise i can not stop the program for copy paste the test, because i not know how to stop the program without close the windows of the interpreter) test:


Julia 0.6, 109 bytes

Link goes to a longer version with two differences:

  1. Checks for primes with hand written function, since the Primes package is not available on TIO.
  2. Iterates over a different date range to not time out.
[s for s in Dates.format(Date(0,1,1):Date(100000,1,1),"YYYYmmdd") if Primes.isprime(parse(s))&&s==reverse(s)]

Try it online!


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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