Palindrome dates

From Rosetta Code
Task
Palindrome dates
You are encouraged to solve this task according to the task description, using any language you may know.

Today   (2020-02-02,   at the time of this writing)   happens to be a palindrome,   without the hyphens,   not only for those countries which express their dates in the   yyyy-mm-dd   format but,   unusually,   also for countries which use the   dd-mm-yyyy   format.


Task

Write a program which calculates and shows the next 15 palindromic dates for those countries which express their dates in the   yyyy-mm-dd   format.

11l

Translation of: Java
V date = Time(2020, 2, 3)
print(‘First 15 palindrome dates after 2020-02-02 are:’)
V count = 0
L count < 15
   V date_formatted = date.format(‘YYYYMMDD’)
   I date_formatted == reversed(date_formatted)
      print(‘date = ’date.format(‘YYYY-MM-DD’))
      count++
   date += TimeDelta(days' 1)
Output:
First 15 palindrome dates after 2020-02-02 are:
date = 2021-12-02
date = 2030-03-02
date = 2040-04-02
date = 2050-05-02
date = 2060-06-02
date = 2070-07-02
date = 2080-08-02
date = 2090-09-02
date = 2101-10-12
date = 2110-01-12
date = 2111-11-12
date = 2120-02-12
date = 2121-12-12
date = 2130-03-12
date = 2140-04-12

Action!

TYPE Date=[
  INT year
  BYTE month
  BYTE day]

BYTE FUNC IsLeapYear(INT y)
  IF y MOD 100=0 THEN
    IF y MOD 400=0 THEN
      RETURN (1)
    ELSE
      RETURN (0)
    FI
  FI
    
  IF y MOD 4=0 THEN
    RETURN (1)
  FI
RETURN (0)

BYTE FUNC GetMaxDay(INT y BYTE m)
  BYTE ARRAY MaxDay=[31 28 31 30 31 30 31 31 30 31 30 31]

  IF m=2 AND IsLeapYear(y)=1 THEN
    RETURN (29)
  FI
RETURN (MaxDay(m-1))

PROC NextDay(Date POINTER d)
  BYTE maxD

  d.day==+1
  maxD=GetMaxDay(d.year,d.month)
  IF d.day>maxD THEN
    d.day=1
    d.month==+1
    IF d.month>12 THEN
      d.month=1
      d.year==+1
    FI
  FI
RETURN

BYTE FUNC IsPalindrome(Date POINTER d)
  INT y

  y=d.year
  IF y/1000#d.day MOD 10 THEN
    RETURN (0)
  FI
  y==MOD 1000
  IF y/100#d.day/10 THEN
    RETURN (0)
  FI
  y==MOD 100
  IF y/10#d.month MOD 10 THEN
    RETURN (0)
  FI
  y==MOD 10
  IF y#d.month/10 THEN
    RETURN (0)
  FI
RETURN (1)

PROC PrintB2(BYTE x)
  IF x<10 THEN
    Put('0)
  FI
  PrintB(x)
RETURN

PROC PrintDateShort(Date POINTER d)
  PrintI(d.year) Put('-)
  PrintB2(d.month) Put('-)
  PrintB2(d.day)
RETURN

PROC Main()
  BYTE count
  Date d

  count=0
  d.year=2020 d.month=2 d.day=3
  WHILE count<15
  DO
    IF IsPalindrome(d) THEN
      PrintDateShort(d) PutE()
      count==+1
    FI
    NextDay(d)
  OD
RETURN
Output:

Screenshot from Atari 8-bit computer

2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

ALGOL 68

Works with: ALGOL 68G version Any - tested with release 2.8.3.win32

Uses the Algol 68G local time routine which is non-standard.

BEGIN # print future palindromic dates                                           #
    # a palindromic date must be of the form demn-nm-ed                          #
    # returns a string representation of n with at least 2 digits                #
    PROC two digits = ( INT n )STRING:
         BEGIN
             STRING result := whole( ABS n, 0 );
             IF ( UPB result - LWB result ) + 1 < 2 THEN "0" +=: result FI;
             IF n < 0 THEN "-" +=: result FI;
             result
         END # two digits # ;
    # possible years for a palindromic date                                      #
    []INT mn     = (  1, 10, 11, 20, 21, 30, 40, 50, 60, 70, 80, 90 );
    # months corresponding to the year for for a palindromic date                #
    []INT nm     = ( 10,  1, 11,  2, 12,  3,  4,  5,  6,  7,  8,  9 );
    # possible centuaries for a palindromic date                                 #
    []INT de     = ( 10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50
                   , 51, 52, 60, 61, 62, 70, 71, 72, 80, 81, 82, 90, 91, 92
                   );
    # days corresponding to the centuary for a palindromic date                  #
    []INT ed     = (  1, 11, 21, 31,  2, 12, 22,  3, 13, 23,  4, 14, 24,  5
                   , 15, 25,  6, 16, 26,  7, 17, 27,  8, 18, 28,  9, 19, 29
                   );
    # max days per month ( february handled specifically in code )               #
    []INT max dd = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
    # current date in local time (Algol 68G extension)                           #
    []INT date   = local time;
    INT   yy now = local time[ 1 ] MOD  100;
    INT   cc now = local time[ 1 ] OVER 100; 
    INT dates to print := 15; # maximum number of dates to print                 #
    FOR c pos FROM LWB de TO UPB de WHILE dates to print > 0 DO
        INT cc = de[ c pos ];
        INT dd = ed[ c pos ];
        FOR y pos FROM LWB nm TO UPB nm WHILE dates to print > 0 DO
            INT mm = nm[ y pos ];
            INT yy = mn[ y pos ];
            IF cc > cc now OR ( cc = cc now AND yy > yy now ) THEN
                # have a possible future date                                    #
                IF dd <= max dd[ mm ]
                OR ( mm = 2 AND dd = 29 AND yy MOD 4 = 0 )
                THEN
                    # have a valid future date                                   #
                    # no need to test yy = 0 as dd = 0 is impossible             #
                    dates to print -:= 1;
                    print( ( two digits( cc )
                           , two digits( yy )
                           , "-"
                           , two digits( mm )
                           , "-"
                           , two digits( dd )
                           , newline
                           )
                         )
                FI
            FI
        OD
    OD
END
Output:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Ada

with Ada.Text_IO;
with Ada.Calendar.Formatting;
with Ada.Calendar.Arithmetic;

procedure Palindrome_Dates is
   Desired_Count : constant := 15;
   Start_Date    : constant String := "2020-01-01 00:00:00";

   use Ada.Calendar;

   function Is_Palindrome_Date (Date : Time) return Boolean is
      Image : String renames Formatting.Image (Date);
   begin
      return
        Image (1) = Image (10) and
        Image (2) = Image (9)  and
        Image (3) = Image (7)  and
        Image (4) = Image (6);
   end Is_Palindrome_Date;

   Date  : Ada.Calendar.Time := Formatting.Value (Start_Date);
   Count : Natural := 0;

   use type Ada.Calendar.Arithmetic.Day_Count;
begin
   loop
      if Is_Palindrome_Date (Date) then
         Ada.Text_IO.Put_Line (Formatting.Image (Date) (1 .. 10));
         Count := Count + 1;
      end if;
      exit when Count = Desired_Count;
      Date := Date + 1;
   end loop;
end Palindrome_Dates;

AppleScript

Procedural

on palindromeDates(startYear, targetNumber)
    script o
        property output : {}
    end script
    
    set counter to 0
    set y to startYear
    repeat until ((counter = targetNumber) or (y > 9999))
        -- Derive a month number from the last two digits of the current year number. It's valid if it's in the range 1 to 12.
        set m to y mod 10 * 10 + y mod 100 div 10
        if ((m > 0) and (m < 13)) then
            -- Derive a day number from the first two digits of the year number.
            set d to y div 100 mod 10 * 10 + y div 1000
            -- It's valid if it's between 1 and 28. Otherwise, if it's between 29 and 31, check that it fits the month and year.
            -- In fact though, it'll only ever be 2 or 12 in the period containing the 15 palindromic dates after 2020.
            if ((d > 0) and ¬
                ((d < 29) ¬
                    or ((d < 31) and ((m is not 2) or ((d is 29) and (y mod 4 is 0) and ((y mod 100 > 0) or (y mod 400 is 0))))) ¬
                    or ((d is 31) and (m is not in {2, 4, 9, 6, 11})))) then
                -- If the figures represent a valid date, add a yyyy-mm-dd format text to the end of the output list.
                tell ((100000000 + y * 10000 + m * 100 + d) as text) to ¬
                    set end of o's output to text 2 thru 5 & ("-" & text 6 thru 7) & ("-" & text 8 thru 9)
                set counter to counter + 1
            end if
        end if
        set y to y + 1
    end repeat
    
    return o's output
end palindromeDates

palindromeDates(2021, 15)
Output:
{"2021-12-02", "2030-03-02", "2040-04-02", "2050-05-02", "2060-06-02", "2070-07-02", "2080-08-02", "2090-09-02", "2101-10-12", "2110-01-12", "2111-11-12", "2120-02-12", "2121-12-12", "2130-03-12", "2140-04-12"}

Functional

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions


-- palinYearsInRange :: Int -> Int -> [String]
on palinYearsInRange(fromYear, toYear)
    
    concatMap(palinDay(iso8601Formatter()), ¬
        enumFromTo(fromYear, toYear))
    
end palinYearsInRange


-- palinDay :: DateFormatter -> Int -> [String]
on palinDay(formatter)
    script
        property fmtr : formatter
        on |λ|(y)
            -- Either an empty list or a list containing a valid
            -- palindromic date for a year in the range [1000 .. 9999]
            if 10000 > y and 999 < y then
                set s to y as string
                set {m, m1, d, d1} to reverse of characters of s
                set mbDate to s & "-" & m & m1 & "-" & d & d1

                if missing value is not ¬
                    (fmtr's dateFromString:(mbDate & ¬
                        "T00:00:00+00:00")) then
                    {mbDate}
                else
                    {}
                end if
            else
                {}
            end if
        end |λ|
    end script
end palinDay


--------------------------- TEST ---------------------------
on run
    set xs to palinYearsInRange(2021, 9999)
    
    unlines({¬
        "Count of palindromic dates [2021..9999]: " & ¬
        ((length of xs) as string), ¬
        "", ¬
        "First 15:", unlines(items 1 thru 15 of xs), "", ¬
        "Last 15:", unlines(items -15 thru -1 of xs)})
end run


-------------------- GENERIC FUNCTIONS ---------------------

-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
    set lng to length of xs
    set acc to {}
    tell mReturn(f)
        repeat with i from 1 to lng
            set acc to acc & (|λ|(item i of xs, i, xs))
        end repeat
    end tell
    return acc
end concatMap


-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m, n)
    if m  n then
        set lst to {}
        repeat with i from m to n
            set end of lst to i
        end repeat
        lst
    else
        {}
    end if
end enumFromTo


-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    -- 2nd class handler function lifted into 1st class script wrapper. 
    if script is class of f then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn


-- iso8601Formatter :: () -> NSISO8601DateFormatter
on iso8601Formatter()
    tell current application
        set formatter to its NSISO8601DateFormatter's alloc's init()
        set formatOptions of formatter to ¬
            (its NSISO8601DateFormatWithInternetDateTime as integer)
        return formatter
    end tell
end iso8601Formatter


-- unlines :: [String] -> String
on unlines(xs)
    -- A single string formed by the intercalation
    -- of a list of strings with the newline character.
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, linefeed}
    set str to xs as text
    set my text item delimiters to dlm
    str
end unlines
Output:
Count of palindromic dates [2021..9999]: 284

First 15:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Last 15:
9170-07-19
9180-08-19
9190-09-19
9201-10-29
9210-01-29
9211-11-29
9220-02-29
9221-12-29
9230-03-29
9240-04-29
9250-05-29
9260-06-29
9270-07-29
9280-08-29
9290-09-29

AutoHotkey

date := 20200202
counter := 0

while (counter < 15) {
    date += 1, days
    date := SubStr(date, 1, 8)
    if (date = reverse(date))
    {
        FormatTime, fdate, % date, yyyy-MM-dd
        output .= fdate "`n"
        counter++
    }
}

MsgBox, 262144, , % output
return

reverse(n){
    for i, v in StrSplit(n)
        output := v output
    return output
}
Output:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

AWK

# syntax: GAWK -f PALINDROME_DATES.AWK
BEGIN {
    show = 15
    year_b = 2020
    year_e = 9999
    split("31,28,31,30,31,30,31,31,30,31,30,31",daynum_array,",") # days per month in non leap year
    for (y=year_b; y<=year_e; y++) {
      daynum_array[2] = (y % 400 == 0 || (y % 4 == 0 && y % 100)) ? 29 : 28
      for (m=1; m<=12; m++) {
        for (d=1; d<=daynum_array[m]; d++) {
          ymd = sprintf("%04d%02d%02d",y,m,d)
          if (substr(ymd,1,1) == substr(ymd,8,1)) { # speed up
            if (ymd == reverse(ymd)) {
              arr[++n] = ymd
            }
          }
        }
      }
    }
    printf("%04d0101-%04d1231=%d years, %d palindromes, showing first and last %d\n",year_b,year_e,year_e-year_b+1,n,show)
    printf("YYYYMMDD YYYYMMDD\n")
    for (i=1; i<=show; i++) {
      printf("%s %s\n",arr[i],arr[n-show+i])
    }
    exit(0)
}
function reverse(str,  i,rts) {
    for (i=length(str); i>=1; i--) {
      rts = rts substr(str,i,1)
    }
    return(rts)
}
Output:
20200101-99991231=7980 years, 285 palindromes, showing first and last 15
YYYYMMDD YYYYMMDD
20200202 91700719
20211202 91800819
20300302 91900919
20400402 92011029
20500502 92100129
20600602 92111129
20700702 92200229
20800802 92211229
20900902 92300329
21011012 92400429
21100112 92500529
21111112 92600629
21200212 92700729
21211212 92800829
21300312 92900929


BASIC

Works with: QBasic
Translation of: FreeBASIC
dateTest$ = ""
total = 0

PRINT "Siguientes 15 fechas palindr¢micas al 2020-02-02:"
FOR anno = 2021 TO 9999
    dateTest$ = LTRIM$(STR$(anno))
    FOR mes = 1 TO 12
        IF mes < 10 THEN dateTest$ = dateTest$ + "0"
        dateTest$ = dateTest$ + LTRIM$(STR$(mes))
        FOR dia = 1 TO 31
            IF mes = 2 AND dia > 28 THEN EXIT FOR
            IF (mes = 4 OR mes = 6 OR mes = 9 OR mes = 11) AND dia > 30 THEN EXIT FOR
            IF dia < 10 THEN dateTest$ = dateTest$ + "0"
            dateTest$ = dateTest$ + LTRIM$(STR$(dia))
            FOR Pal = 1 TO 4
                IF MID$(dateTest$, Pal, 1) <> MID$(dateTest$, 9 - Pal, 1) THEN EXIT FOR
            NEXT Pal
            IF Pal = 5 THEN
               total = total + 1
               IF total <= 15 THEN PRINT LEFT$(dateTest$, 4); "-"; MID$(dateTest$, 5, 2); "-"; RIGHT$(dateTest$, 2)
            END IF
            IF total > 15 THEN
               EXIT FOR: EXIT FOR: EXIT FOR
            END IF
            dateTest$ = LEFT$(dateTest$, 6)
        NEXT dia
        dateTest$ = LEFT$(dateTest$, 4)
    NEXT mes
    dateTest$ = ""
NEXT anno
END
Output:
Igual que la entrada de FreeBASIC.

BASIC256

Translation of: FreeBASIC
dateTest = ""
mes = 0 : dia = 0 : anno = 0 : Pal = 0
total = 0
print "Siguientes 15 fechas palindrómicas al 2020-02-02:"
for anno = 2021 to 9999
	dateTest = ltrim(string(anno))
	for mes = 1 to 12
		if mes < 10 then dateTest = dateTest + "0"
		dateTest = dateTest + ltrim(string(mes))
		for dia = 1 to 31
			if mes = 2 and dia > 28 then exit for
			if (mes = 4 or mes = 6 or mes = 9 or mes = 11) and dia > 30 then exit for
			if dia < 10 then dateTest = dateTest + "0"
			dateTest = dateTest + ltrim(string(dia))
			for Pal = 1 to 4
				if mid(dateTest, Pal, 1) <> mid(dateTest, 9 - Pal, 1) then exit for
			next Pal
			if Pal = 5 then
				total += 1
				if total <= 15 then print left(dateTest,4);"-";mid(dateTest,5,2);"-";right(dateTest,2)
			end if
			if total > 15 then exit for : exit for : exit for
			dateTest = left(dateTest, 6)
		next dia
		dateTest = left(dateTest, 4)
	next mes
	dateTest = ""
next anno
end
Output:
Igual que la entrada de FreeBASIC.

BBC BASIC

      INSTALL @lib$ + "DATELIB"
      DIM B% 8
      TestDate%=FN_today
      REPEAT
        $B%=FN_date$(TestDate%, "yyyyMMdd")
        FOR I%=0 TO 3
          IF ?(B% + I%) <> ?(B% + 7 - I%) EXIT FOR
        NEXT
        IF I%=4 PRINT FN_date$(TestDate%, "yyyy-MM-dd")
        TestDate%+=1
      UNTIL VPOS=15
      END
Output:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

C

This only works if time_t is a 64-bit type.

#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

bool is_palindrome(const char* str) {
    size_t n = strlen(str);
    for (size_t i = 0; i + 1 < n; ++i, --n) {
        if (str[i] != str[n - 1])
            return false;
    }
    return true;
}

int main() {
    time_t timestamp = time(0);
    const int seconds_per_day = 24*60*60;
    int count = 15;
    char str[32];
    printf("Next %d palindrome dates:\n", count);
    for (; count > 0; timestamp += seconds_per_day) {
        struct tm* ptr = gmtime(&timestamp);
        strftime(str, sizeof(str), "%Y%m%d", ptr);
        if (is_palindrome(str)) {
            strftime(str, sizeof(str), "%F", ptr);
            printf("%s\n", str);
            --count;
        }
    }
    return 0;
}
Output:
Next 15 palindrome dates:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

C#

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    static void Main()
    {
        foreach (var date in PalindromicDates(2021).Take(15)) WriteLine(date.ToString("yyyy-MM-dd"));
    }

    public static IEnumerable<DateTime> PalindromicDates(int startYear) {
        for (int y = startYear; ; y++) {
            int m = Reverse(y % 100);
            int d = Reverse(y / 100);
            if (IsValidDate(y, m, d, out var date)) yield return date;
        }

        int Reverse(int x) => x % 10 * 10 + x / 10;
        bool IsValidDate(int y, int m, int d, out DateTime date) => DateTime.TryParse($"{y}-{m}-{d}", out date);
    }
}
Output:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

C++

Library: Boost
#include <iostream>
#include <string>
#include <boost/date_time/gregorian/gregorian.hpp>

bool is_palindrome(const std::string& str) {
    for (size_t i = 0, j = str.size(); i + 1 < j; ++i, --j) {
        if (str[i] != str[j - 1])
            return false;
    }
    return true;
}

int main() {
    using boost::gregorian::date;
    using boost::gregorian::day_clock;
    using boost::gregorian::date_duration;
    
    date today(day_clock::local_day());
    date_duration day(1);
    int count = 15;
    std::cout << "Next " << count << " palindrome dates:\n";
    for (; count > 0; today += day) {
        if (is_palindrome(to_iso_string(today))) {
            std::cout << to_iso_extended_string(today) << '\n';
            --count;
        }
    }
    return 0;
}
Output:
Next 15 palindrome dates:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Clojure

(defn valid-date? [[y m d]]
  (and (<= 1 m 12)
       (<= 1 d 31)))

(defn date-str [[y m d]]
  (format "%4d-%02d-%02d" y m d))

(defn yr->date [y]
  (let [[_ m d] (re-find #"(..)(..)" (apply str (reverse (str y))))]
    [y (Long. m) (Long. d)]))

(defn palindrome-dates [start-yr n]
  (->> (iterate inc start-yr)
       (map yr->date)
       (filter valid-date?)
       (map date-str)
       (take n)))
Output:
("2021-12-02" "2030-03-02" "2040-04-02" "2050-05-02" "2060-06-02" "2070-07-02" "2080-08-02" "2090-09-02" "2101-10-12" "2110-01-12" "2111-11-12" "2120-02-12" "2121-12-12" "2130-03-12" "2140-04-12")

F#

// palindrome_dates.fsx
open System

let is_palindrome_date =
    let date_string (date: DateTime) = date.ToString "yyyyMMdd"
    let is_palindrome s =
        let rev_string = Seq.rev >> Seq.map string >> String.concat ""
        s = rev_string s
    date_string >> is_palindrome

let palindrome_dates =
    let rec loop date =
        seq {
            if is_palindrome_date date
            then
                yield date
                yield! loop (date.AddDays 1.0)
            else
                yield! loop (date.AddDays 1.0)
        }
    loop DateTime.Now

let print_date =
    let iso_string (date: DateTime) = date.ToString "yyyy-MM-dd"
    iso_string >> printfn "%s"

palindrome_dates
|> Seq.take 15
|> Seq.iter print_date
Output:
> dotnet fsi palindrome_dates.fsx 
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Factor

Brute force

A simple brute force solution that repeatedly increments a timestamp's day by one and checks whether it's a palindrome:

Works with: Factor version 0.99 2020-01-23
USING: calendar calendar.format io kernel lists lists.lazy
sequences sets ;

: palindrome-dates ( -- list )
    2020 2 2 <date> [ 1 days time+ ] lfrom-by
    [ timestamp>ymd ] lmap-lazy
    [ "-" without dup reverse = ] lfilter ;

15 palindrome-dates ltake [ print ] leach
Output:
2020-02-02
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12

Faster

A faster version that directly generates palindromic numbers such as 20200202 and keeps those which are valid dates:

Works with: Factor version 0.99 2020-01-23
USING: calendar calendar.format continuations io kernel lists
lists.lazy math math.functions math.parser math.ranges sequences ;

: create-palindrome ( n odd? -- m )
    dupd [ 10 /i ] when swap [ over 0 > ]
    [ 10 * [ 10 /mod ] [ + ] bi* ] while nip ;

: palindromes ( -- list )
    3 lfrom [
        10 swap ^ dup 10 * [a,b)
        [ [ t create-palindrome ] map ]
        [ [ f create-palindrome ] map ] bi
        [ sequence>list ] bi@ lappend
    ] lmap-lazy lconcat [ 20200202 >= ] lfilter ;

: palindrome-dates ( -- list )
    palindromes [
        number>string 4 cut* 2 cut [ string>number ] tri@
        [ <date> ] [ 4drop f ] recover
    ] lmap-lazy [ f = not ] lfilter ;

"10,000th palindrome date after 2020-02-02: " write
10,000 palindrome-dates lnth timestamp>ymd print
Output:
10,000th palindrome date after 2020-02-02: 1250101-05-21


FreeBASIC

Dim As String dateTest = ""
Dim As Integer Pal =0, total = 0
Print "Siguientes 15 fechas palindr¢micas al 2020-02-02:"
For anno As Integer = 2021 To 9999
    dateTest = Ltrim(Str(anno))
    For mes As Integer = 1 To 12
        If mes < 10 Then dateTest = dateTest + "0"
        dateTest += Ltrim(Str(mes))
        For dia As Integer = 1 To 31
            If mes = 2 And dia > 28 Then Exit For
            If (mes = 4 Or mes = 6 Or mes = 9 Or mes = 11) And dia > 30 Then Exit For
            If dia < 10 Then dateTest += "0"
            dateTest = dateTest + Ltrim(Str(dia))
            For Pal = 1 To 4
                If Mid(dateTest, Pal, 1) <> Mid(dateTest, 9 - Pal, 1) Then Exit For
            Next Pal
            If Pal = 5 Then 
                total += 1
                If total <= 15 Then Print Left(dateTest,4);"-";Mid(dateTest,5,2);"-";Right(dateTest,2)
            End If
            if total > 15 then Exit For : Exit For : Exit For            
            dateTest = Left(dateTest, 6)
        Next dia
        dateTest = Left(dateTest, 4)
    Next mes
    dateTest = ""
Next anno
Sleep
Output:
Siguientes 15 fechas palindrómicas al 2020-02-02:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12


Go

Simple brute force as speed is not an issue here.

package main

import (
    "fmt"
    "time"
)

func reverse(s string) string {
    chars := []rune(s)
    for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
        chars[i], chars[j] = chars[j], chars[i]
    }
    return string(chars)
}

func main() {
    const (
        layout  = "20060102"
        layout2 = "2006-01-02"
    )
    fmt.Println("The next 15 palindromic dates in yyyymmdd format after 20200202 are:")
    date := time.Date(2020, 2, 2, 0, 0, 0, 0, time.UTC)
    count := 0
    for count < 15 {
        date = date.AddDate(0, 0, 1)
        s := date.Format(layout)
        r := reverse(s)
        if r == s {
            fmt.Println(date.Format(layout2))
            count++
        }
    }
}
Output:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Or, a more ambitious version.

package main

import (
    "fmt"
    "sort"
    "time"
)

func reverse(s string) string {
    chars := []rune(s)
    for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
        chars[i], chars[j] = chars[j], chars[i]
    }
    return string(chars)
}

func findIndex(sl []string, s string) int {
    return sort.Search(len(sl), func(i int) bool {
        return sl[i] > s
    })
}

func main() {
    const (
        layout  = "20060102"
        layout2 = "2006-01-02"
    )
    palins := []string{}
    for i := 0; i < 10000; i++ {
        y := fmt.Sprintf("%04d", i)
        r := reverse(y)
        if r[:2] > "12" || r[2:] > "31" {
            continue
        }
        d := fmt.Sprintf("%s%s", y, r)
        t, err := time.Parse(layout, d)
        if err == nil {
            palins = append(palins, t.Format(layout2))
        }
    }
    le := len(palins)
    i1 := findIndex(palins, "1001-01-01")
    i2 := findIndex(palins, "2020-02-02")
    fmt.Printf("There are %d palindromic dates after 0000-01-01 of which:\n", le)
    fmt.Printf("          %d are after 1000-01-01\n", le-i1)
    fmt.Printf("          %d are after 2020-02-02\n", le-i2)
    fmt.Println("\nThe first 15 after 2020-02-02 are:")
    for i := 0; i < 15; i++ {
        if i != 0 && i%5 == 0 {
            fmt.Println()
        }
        fmt.Printf("%s   ", palins[i+i2])
    }
    fmt.Println("\n\nThe last 15 before 9999-12-31 are:")
    for i := 15; i >= 1; i-- {
        if i != 15 && i%5 == 0 {
            fmt.Println()
        }
        fmt.Printf("%s   ", palins[le-i])
    }
    fmt.Println()
}
Output:
There are 366 palindromic dates after 0000-01-01 of which:
          331 are after 1000-01-01
          284 are after 2020-02-02

The first 15 after 2020-02-02 are:
2021-12-02   2030-03-02   2040-04-02   2050-05-02   2060-06-02   
2070-07-02   2080-08-02   2090-09-02   2101-10-12   2110-01-12   
2111-11-12   2120-02-12   2121-12-12   2130-03-12   2140-04-12   

The last 15 before 9999-12-31 are:
9170-07-19   9180-08-19   9190-09-19   9201-10-29   9210-01-29   
9211-11-29   9220-02-29   9221-12-29   9230-03-29   9240-04-29   
9250-05-29   9260-06-29   9270-07-29   9280-08-29   9290-09-29  

Haskell

import Data.List (unfoldr)
import Data.List.Split (chunksOf)
import Data.Maybe (mapMaybe)
import Data.Time.Calendar (Day, fromGregorianValid)
import Data.Tuple (swap)

-------------------- PALINDROMIC DATES -------------------

palinDates :: [Day]
palinDates = mapMaybe palinDay [2021 .. 9999]

palinDay :: Integer -> Maybe Day
palinDay y = fromGregorianValid y m d
  where
    [m, d] = unDigits <$> chunksOf 2 
      (reversedDecimalDigits (fromInteger y))


--------------------------- TEST -------------------------
main :: IO ()
main =
  let n = length palinDates
   in putStrLn ("Count of palindromic dates [2021..9999]: " 
        <> show n) >>
      putStrLn "\nFirst 15:" >>
      mapM_ print (take 15 palinDates) >>
      putStrLn "\nLast 15:" >>
      mapM_ print (take 15 (drop (n - 15) palinDates))


------------------------- GENERIC ------------------------

reversedDecimalDigits :: Int -> [Int]
reversedDecimalDigits = unfoldr go
  where
    go n
      | 0 < n = Just $ swap (quotRem n 10)
      | otherwise = Nothing

unDigits :: [Int] -> Int
unDigits = foldl ((+) . (10 *)) 0
Output:
Count of palindromic dates [2021..9999]: 284

First 15:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Last 15:
9170-07-19
9180-08-19
9190-09-19
9201-10-29
9210-01-29
9211-11-29
9220-02-29
9221-12-29
9230-03-29
9240-04-29
9250-05-29
9260-06-29
9270-07-29
9280-08-29
9290-09-29

J

Using J's date routines:

task=: {{
  r=. ''
  days=. todayno 2020 02 02
  while. 15 > #r do.
    days=. ({:days)+1+i.1e4
    r=. r, days#~(-:|.)"1":,.1 todate days
  end.
  15 10{.isotimestamp todate r
}}
   task''
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Java

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class PalindromeDates {

    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2020, 2, 3);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        DateTimeFormatter formatterDash = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        System.out.printf("First 15 palindrome dates after 2020-02-02 are:%n");
        for ( int count = 0 ; count < 15 ; date = date.plusDays(1) ) {
            String dateFormatted = date.format(formatter);
            if ( dateFormatted.compareTo(new StringBuilder(dateFormatted).reverse().toString()) == 0 ) {
                count++;
                System.out.printf("date = %s%n", date.format(formatterDash));
            }
        }
    }

}
Output:
First 15 palindrome dates after 2020-02-02 are:
date = 2021-12-02
date = 2030-03-02
date = 2040-04-02
date = 2050-05-02
date = 2060-06-02
date = 2070-07-02
date = 2080-08-02
date = 2090-09-02
date = 2101-10-12
date = 2110-01-12
date = 2111-11-12
date = 2120-02-12
date = 2121-12-12
date = 2130-03-12
date = 2140-04-12

JavaScript

Procedural

/**
 * Adds zeros for 1 digit days/months
 * @param date: string
 */
const addMissingZeros = date => (/^\d$/.test(date) ? `0${date}` : date);

/**
 * Formats a Date to a string. If readable is false,
 * string is only numbers (used for comparison), else
 * is a human readable date.
 * @param date: Date
 * @param readable: boolean
 */
const formatter = (date, readable) => {
  const year = date.getFullYear();
  const month = addMissingZeros(date.getMonth() + 1);
  const day = addMissingZeros(date.getDate());

  return readable ? `${year}-${month}-${day}` : `${year}${month}${day}`;
};

/**
 * Returns n (palindromesToShow) palindrome dates
 * since start (or 2020-02-02)
 * @param start: Date
 * @param palindromesToShow: number
 */
function getPalindromeDates(start, palindromesToShow = 15) {
  let date = start || new Date(2020, 3, 2);

  for (
    let i = 0;
    i < palindromesToShow;
    date = new Date(date.setDate(date.getDate() + 1))
  ) {
    const formattedDate = formatter(date);
    if (formattedDate === formattedDate.split("").reverse().join("")) {
      i++;
      console.log(formatter(date, true));
    }
  }
}

getPalindromeDates();
Output:
2021-12-02 ​
2030-03-02 ​
2040-04-02 ​
2050-05-02 ​
2060-06-02 ​
2070-07-02 ​
2080-08-02 ​
2090-09-02 
2101-10-12 ​
2110-01-12 ​
2111-11-12 ​
2120-02-12​
2121-12-12 ​
2130-03-12 ​
2140-04-12 ​

Functional

(() => {
    'use strict';

    // ----------------- PALINDROME DATES ------------------

    // palindromeDate :: Int -> [String]
    const palindromeDate = year => {
        // Either an empty list, if no palindromic date
        // can be derived from this year, or a list
        // containing a palindromic IS0 8601 date.
        const
            s = year.toString(),
            r = reverse(s),
            iso = [
                s,
                r.slice(0, 2),
                r.slice(2, 4)
            ].join('-');
        return isNaN(new Date(iso)) ? (
            []
        ) : [iso];
    };

    // ----------------------- TEST ------------------------
    const main = () => {
        const
            xs = enumFromTo(2021)(9999).flatMap(
                palindromeDate
            );
        return [
            `Count of palindromic dates [2021..9999]: ${
                xs.length
            }`,
            '',
            `First 15: ${'\n' + xs.slice(0, 15).join('\n')}`,
            '',
            `Last 15: ${'\n' + xs.slice(-15).join('\n')}`
        ].join('\n');
    };

    // ----------------- GENERIC FUNCTIONS -----------------

    // enumFromTo :: Int -> Int -> [Int]
    const enumFromTo = m =>
        n => Array.from({
            length: 1 + n - m
        }, (_, i) => m + i);

    // reverse :: [a] -> [a]
    const reverse = xs =>
        'string' !== typeof xs ? (
            xs.slice(0).reverse()
        ) : xs.split('').reverse().join('');

    // MAIN ---
    return main();
})();
Output:
Count of palindromic dates [2021..9999]: 284

First 15: 
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Last 15: 
9170-07-19
9180-08-19
9190-09-19
9201-10-29
9210-01-29
9211-11-29
9220-02-29
9221-12-29
9230-03-29
9240-04-29
9250-05-29
9260-06-29
9270-07-29
9280-08-29
9290-09-29

jq

Adapted from Wren

Works with: jq

Also works with gojq, the Go implementation of jq

Also works with fq, a Go implementation of a large subset of jq

# input and output:  [year, month, day] using month=1 for Jan
# add the number of days to the input date
def addDays($days):
  . as [$y,$m,$d]
  | [$y,$m-1,$d + $days,0,0,0,0,0] | mktime | gmtime[0:3] | .[1]+=1;

# input: [year, month, day], an array of integers
# output:  [yyyy, mm, dd] , an array of strings,
def yyyymmdd:
  def l($len): tostring | ($len - length) as $l | ("0" * $l)[:$l] + .;
  [(.[0]|l(4)), (.[1]|l(2)),  (.[2]|l(2))] ;
  
# input: [year, month, day] using month=1 for Jan
def isPalDate:
  yyyymmdd  | add  | explode  | . == reverse;

def task:
  "The next 15 palindromic dates in yyyy-mm-dd format after 2020-02-02 are:",
  ( [2020, 2, 2] 
    | addDays(1)
    | limit(15; recurse(addDays(1)) | select(isPalDate) )
    | yyyymmdd
    | join("-") );

task
Output:

As for Wren.


Julia

Uses the built-in Dates package to check date validity but not for iteration.

using Dates
 
function datepalindromes(nextcount=20)
    println("Date palindromes:")
    count, d = 0, Date(1000, 1, 1)
    for year in 2021:9200
        try
            dig = digits(year)
            month = 10 * dig[1] + dig[2]
            day = 10 * dig[3] + dig[4]
            d = Date(year, month, day)
        catch
            continue
        end
        println(d)
        count += 1
        if count >= nextcount
            break
        end
    end
end
 
datepalindromes()
Output:
Date palindromes:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12
2150-05-12
2160-06-12
2170-07-12
2180-08-12
2190-09-12

Mathematica / Wolfram Language

today = DateList[Today];
res = {};
i = 0;
While[Length[res] < 15,
 date = DatePlus[today, i];
 ds = DateString[date, {"Year", "Month", "Day"}];
 If[PalindromeQ[ds],
  AppendTo[res, date]
  ];
 i++;
 ]
Column[DateString[#, {"Year", "-", "Month", "-", "Day"}] & /@ res]
Output:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Nim

import strformat, times

func digits(n: int): seq[int] =
  var n = n
  while n != 0:
    result.add n mod 10
    n = n div 10

echo "First 15 palindrome dates after 2020-02-02:"
var count = 0
var year = 2021
while count != 15:
  let d = year.digits
  let monthNum = 10 * d[0] + d[1]
  let dayNum = 10 * d[2] + d[3]
  if monthNum in 1..12:
    if dayNum <= getDaysInMonth(Month(monthNum), year):
      # Date is valid.
      echo &"{year}-{monthNum:02}-{dayNum:02}"
      inc count
  inc year
Output:
First 15 palindrome dates after 2020-02-02:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Perl

Date calculation

The more robust solution, using a date/time module.

use Time::Piece;
my $d = Time::Piece->strptime("2020-02-02", "%Y-%m-%d");

for (my $k = 1 ; $k <= 15 ; $d += Time::Piece::ONE_DAY) {
    my $s = $d->strftime("%Y%m%d");
    if ($s eq reverse($s) and ++$k) {
        print $d->strftime("%Y-%m-%d\n");
    }
}
Output:
2020-02-02
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12

String manipulation

Given the limited look-ahead required by the task, processing date-like strings can also work.

Library: ntheory
use strict;
use warnings;
use feature 'say';
use ntheory qw/forsetproduct/;

my $start = '2020-02-02' =~ s/-//gr;
my($y) = substr($start,0,4);

my(@dates,$cnt);
forsetproduct { push @dates, "@_" } [$y..$y+999],['01'..'12'],['01'..'31'];
for (@dates) {
    (my $date = $_) =~ s/ //g;
    next unless $date > $start and $date eq reverse $date;
    say s/ /-/gr;
    last if 15 == ++$cnt;
}
Output:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Phix

While parse_date_string() copes with 1/2/4 digit years, it (reasonably enough) throws a wobbly given 5-digit years and beyond.

with javascript_semantics
include builtins\timedate.e 
sequence res = {}
for d=2021 to 9999 do
    string s = sprintf("%4d",d),
           t = reverse(s)
    s &= "-"&t[1..2]&"-"&t[3..4]
    sequence td = parse_date_string(s, {"YYYY-MM-DD"})
    if timedate(td) then res = append(res,s) end if
end for
printf(1,"Count of palindromic dates [2021..9999]: %d\n\n",length(res))
printf(1,"first 15:\n%s\n",join_by(res[1..15],3,5))
printf(1,"last 15:\n%s\n",join_by(res[-15..-1],3,5))
Output:
Count of palindromic dates [2021..9999]: 284

first 15:
2021-12-02   2050-05-02   2080-08-02   2110-01-12   2121-12-12
2030-03-02   2060-06-02   2090-09-02   2111-11-12   2130-03-12
2040-04-02   2070-07-02   2101-10-12   2120-02-12   2140-04-12

last 15:
9170-07-19   9201-10-29   9220-02-29   9240-04-29   9270-07-29
9180-08-19   9210-01-29   9221-12-29   9250-05-29   9280-08-29
9190-09-19   9211-11-29   9230-03-29   9260-06-29   9290-09-29

PureBasic

NewList pdates.s()

Procedure.b IsLeap(y.i)
  ProcedureReturn Bool( y % 4 = 0 ) & Bool( y % 100 <> 0 ) | Bool( y % 400 = 0 )
EndProcedure

If OpenConsole("")=0 : End 1 : EndIf

For j=2021 To 9999
  For m=1 To 12
    tm2=28+1*IsLeap(j)
    For t=1 To 31
      If m=2 And t>tm2 : Break : EndIf      
      If (m=4 Or m=6 Or m=9 Or m=11) And t>30 : Break : EndIf      
      s$=Str(j)+RSet(Str(m),2,"0")+RSet(Str(t),2,"0")
      If ReverseString(s$)=s$
        AddElement(pdates()) : pdates()=Mid(s$,1,4)+"-"+Mid(s$,5,2)+"-"+Mid(s$,7,2)
      EndIf
    Next t
  Next m
Next j

PrintN("Count of palindromic dates [2021..9999]: "+Str(ListSize(pdates())))
FirstElement(pdates())
t$="First 15:"
For x=1 To 2  
  PrintN(~"\n"+t$)
  For y=1 To 15 : PrintN(pdates()) : NextElement(pdates()) : Next  
  t$="Last 15:" : SelectElement(pdates(),ListSize(pdates())-15)
Next
Input() : End
Output:
Count of palindromic dates [2021..9999]: 284

First 15:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Last 15:
9170-07-19
9180-08-19
9190-09-19
9201-10-29
9210-01-29
9211-11-29
9220-02-29
9221-12-29
9230-03-29
9240-04-29
9250-05-29
9260-06-29
9270-07-29
9280-08-29
9290-09-29

Python

Functional

Defined in terms of string reversal:

Works with: Python version 3.7
'''Palindrome dates'''

from datetime import datetime
from itertools import chain


# palinDay :: Int -> [ISO Date]
def palinDay(y):
    '''A possibly empty list containing the palindromic
       date for the given year, if such a date exists.
    '''
    s = str(y)
    r = s[::-1]
    iso = '-'.join([s, r[0:2], r[2:]])
    try:
        datetime.strptime(iso, '%Y-%m-%d')
        return [iso]
    except ValueError:
        return []


# --------------------------TEST---------------------------
# main :: IO ()
def main():
    '''Count and samples of palindromic dates [2021..9999]
    '''
    palinDates = list(chain.from_iterable(
        map(palinDay, range(2021, 10000))
    ))
    for x in [
            'Count of palindromic dates [2021..9999]:',
            len(palinDates),
            '\nFirst 15:',
            '\n'.join(palinDates[0:15]),
            '\nLast 15:',
            '\n'.join(palinDates[-15:])
    ]:
        print(x)


# MAIN ---
if __name__ == '__main__':
    main()
Output:
Count of palindromic dates [2021..9999]:
284

First 15:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Last 15:
9170-07-19
9180-08-19
9190-09-19
9201-10-29
9210-01-29
9211-11-29
9220-02-29
9221-12-29
9230-03-29
9240-04-29
9250-05-29
9260-06-29
9270-07-29
9280-08-29
9290-09-29


Or, defined in terms of integer operations, rather than string reversals:

Works with: Python version 3.7
'''Palindrome dates'''

from functools import reduce
from itertools import chain
from datetime import date


# palinDay :: Integer -> [ISO Date]
def palinDay(y):
    '''A possibly empty list containing the palindromic
       date for the given year, if such a date exists.
    '''
    [m, d] = [undigits(pair) for pair in chunksOf(2)(
        reversedDecimalDigits(y)
    )]
    return [] if (
        1 > m or m > 12 or 31 < d
    ) else validISODate((y, m, d))


# --------------------------TEST---------------------------
# main :: IO ()
def main():
    '''Count and samples of palindromic dates [2021..9999]
    '''
    palinDates = list(chain.from_iterable(
        map(palinDay, range(2021, 10000))
    ))
    for x in [
            'Count of palindromic dates [2021..9999]:',
            len(palinDates),
            '\nFirst 15:',
            '\n'.join(palinDates[0:15]),
            '\nLast 15:',
            '\n'.join(palinDates[-15:])
    ]:
        print(x)


# -------------------------GENERIC-------------------------

# Just :: a -> Maybe a
def Just(x):
    '''Constructor for an inhabited Maybe (option type) value.
       Wrapper containing the result of a computation.
    '''
    return {'type': 'Maybe', 'Nothing': False, 'Just': x}


# Nothing :: Maybe a
def Nothing():
    '''Constructor for an empty Maybe (option type) value.
       Empty wrapper returned where a computation is not possible.
    '''
    return {'type': 'Maybe', 'Nothing': True}


# chunksOf :: Int -> [a] -> [[a]]
def chunksOf(n):
    '''A series of lists of length n, subdividing the
       contents of xs. Where the length of xs is not evenly
       divible, the final list will be shorter than n.
    '''
    return lambda xs: reduce(
        lambda a, i: a + [xs[i:n + i]],
        range(0, len(xs), n), []
    ) if 0 < n else []


# reversedDecimalDigits :: Int -> [Int]
def reversedDecimalDigits(n):
    '''A list of the decimal digits of n,
       in reversed sequence.
    '''
    return unfoldr(
        lambda x: Nothing() if (
            0 == x
        ) else Just(divmod(x, 10))
    )(n)


# unDigits :: [Int] -> Int
def undigits(xs):
    '''An integer derived from a list of decimal digits
    '''
    return reduce(lambda a, x: a * 10 + x, xs, 0)


# unfoldr(lambda x: Just((x, x - 1)) if 0 != x else Nothing())(10)
# -> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
# unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
def unfoldr(f):
    '''Dual to reduce or foldr.
       Where catamorphism reduces a list to a summary value,
       the anamorphic unfoldr builds a list from a seed value.
       As long as f returns Just(a, b), a is prepended to the list,
       and the residual b is used as the argument for the next
       application of f.
       When f returns Nothing, the completed list is returned.
    '''
    def go(v):
        xr = v, v
        xs = []
        while True:
            mb = f(xr[0])
            if mb.get('Nothing'):
                return xs
            else:
                xr = mb.get('Just')
                xs.append(xr[1])
        return xs
    return go


# validISODate :: (Int, Int, Int) -> [Date]
def validISODate(ymd):
    '''A possibly empty list containing the
       ISO8601 string for a date, if that date exists.
    '''
    try:
        return [date(*ymd).isoformat()]
    except ValueError:
        return []


# MAIN ---
if __name__ == '__main__':
    main()
Output:
Count of palindromic dates [2021..9999]:
284

First 15:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Last 15:
9170-07-19
9180-08-19
9190-09-19
9201-10-29
9210-01-29
9211-11-29
9220-02-29
9221-12-29
9230-03-29
9240-04-29
9250-05-29
9260-06-29
9270-07-29
9280-08-29
9290-09-29

QB64

'Task
' Write a program which calculates and shows the next 15 palindromic dates
' for those countries which express their dates in the   yyyy-mm-dd format
' and for those countries which express their dates int dd-mm-yyyy format
' the user will choose what format to use for calculating
Dim dateTest As String, Mounth As Integer, Day As Integer, Year As Integer, Pal As Integer, choice As Integer
dateTest = ""
Mounth = 0
Day = 0
Year = 0
Pal = 0
choice = 0
Print " choose date format:"
Print " press 1 for using YYYY-MM-DD format"
Print " press 2 for using DD-MM-YYYY format"

While choice < 1 Or choice > 2
    choice = Val(InKey$)
Wend
Print " Well, you have choosen format number "; choice
Sleep 2
For Year = 2020 To 2420
    dateTest = LTrim$(Str$(Year))
    For Mounth = 1 To 12
        If Mounth < 10 Then k$ = "0" Else k$ = ""

        If choice = 1 Then
            dateTest = dateTest + k$ + LTrim$(Str$(Mounth))
        Else
            dateTest = k$ + LTrim$(Str$(Mounth)) + dateTest
        End If


        For Day = 1 To 31
            If Mounth = 2 And Day > 28 Then Exit For
            If (Mounth = 4 Or Mounth = 6 Or Mounth = 9 Or Mounth = 11) And Day > 30 Then Exit For
            If Day < 10 Then k$ = "0" Else k$ = ""
            If choice = 1 Then
                dateTest = dateTest + k$ + LTrim$(Str$(Day))
            Else
                dateTest = k$ + LTrim$(Str$(Day)) + dateTest
            End If
            'Print dateTest: Sleep
            For Pal = 1 To 4
                If Mid$(dateTest, Pal, 1) <> Mid$(dateTest, 9 - Pal, 1) Then Exit For
            Next
            If Pal = 5 Then Print dateTest
            If choice = 1 Then
                dateTest = Left$(dateTest, 6)
            Else
                dateTest = Right$(dateTest, 6)
            End If
        Next
        If choice = 1 Then
            dateTest = Left$(dateTest, 4)
        Else
            dateTest = Right$(dateTest, 4)
        End If
    Next
    dateTest = ""
Next

Quackery

  [ dup 400 mod 0 = iff
      [ drop true ]  done
    dup 100 mod 0 = iff
      [ drop false ] done
    4 mod 0 = ]               is leap       (     y --> b           )

  [ 1 -
    [ table
      31 [ dup leap 28 + ]
      31 30 31 30 31 31 30
      31 30 31 ]
    do nip ]                  is monthdays  (   y m --> n           )

  [ 1+ dip [ 2dup monthdays ]
    tuck < while
    drop 1+ 1
    over 13 = if
      [ 2drop 1+ 1 1 ] ]      is nextday    ( y m d --> y m d       )


  [ dip 2dup dup dip unrot ]  is 3dup       ( a b c --> a b c a b c )

  [ swap 100 * +
    swap 10000 * +
    number$ ]                 is date$      ( y m d --> $           )

  [ dup reverse = ]           is palindrome (     $ --> b           )

  [ char - swap 4 stuff
    char - swap 7 stuff ]     is +dashes    (     $ --> $           )

  [] temp put
  2020 02 02
  [ nextday
    3dup date$
    dup palindrome iff
      [ temp take
        swap nested join
        temp put ]
    else drop
    temp share
    size 15 = until ]
  drop 2drop
  temp take witheach
    [ +dashes echo$ cr ]
Output:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12


Raku

(formerly Perl 6)

Works with: Rakudo version 2020.01

Pretty basic, but good enough. Could start earlier but 3/2/1 digit years require different handling that isn't necessary for this task. (And would be pretty pointless anyway assuming we need 2 digits for the month and two digits for the day. ISO:8601 anybody?)

my $start = '1000-01-01';
 
my @palindate = {
     state $year = $start.substr(0,4);
     ++$year;
     my $m = $year.substr(2, 2).flip;
     my $d = $year.substr(0, 2).flip;
     next if not try Date.new("$year-$m-$d");
     "$year-$m-$d"
} … *;
 
my $date-today = Date.today; # 2020-02-02
 
my $k = @palindate.first: { Date.new($_) > $date-today }, :k;
 
say join "\n", @palindate[$k - 1 .. $k + 14];

say "\nTotal number of four digit year palindrome dates:\n" ~
my $four = @palindate.first( { .substr(5,1) eq '-' }, :k );
say "between {@palindate[0]} and {@palindate[$four - 1]}.";

my $five = @palindate.first: { .substr(6,1) eq '-' }, :k;

say "\nTotal number of five digit year palindrome dates:\n" ~
+@palindate[$four .. $five]
Output:
2020-02-02
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Total number of four digit year palindrome dates:
331
between 1001-10-01 and 9290-09-29.

Total number of five digit year palindrome dates:
3303

REXX

This REXX version works with   Regina REXX.

The   date   BIF   (with the   base   argument)   converts a date to the number of years since the beginning of
the Gregorian calendar,   the date is in the   ISO   format   (International Standards Organization   8601:2004).

/*REXX program finds & displays the next  N  palindromic dates starting after 2020─02─02*/
/*                                                                      ─────           */
parse arg n from .                               /*obtain optional argumets from the CL*/
if    n=='' |    n==","  then    n= 15           /*Not specified?  Then use the default.*/
if from=='' | from==","  then from= '2020-02-02' /* "      "         "   "   "     "    */
#= 0                                             /*the count of palindromic dates so far*/
     do j=date('Base', from, "ISO")+1 until #==n /*find palindromic dates 'til  N  found*/
     aDate= date('ISO', j, "Base")               /*convert a "base" date to ISO format. */
     $= space( translate(aDate, , '-'),  0)      /*elide the dashes  (-)  in this date. */
     if $\==reverse($)  then iterate             /*Not palindromic?  Then skip this date*/
     say 'a palindromic date: '        aDate     /*display a palindromic date ──► term. */
     #= # + 1                                    /*bump the counter of palindromic dates*/
     end   /*j*/                                 /*stick a fork in it,  we're all done. */
output   when using the default inputs:
a palindromic date:  2021-12-02
a palindromic date:  2030-03-02
a palindromic date:  2040-04-02
a palindromic date:  2050-05-02
a palindromic date:  2060-06-02
a palindromic date:  2070-07-02
a palindromic date:  2080-08-02
a palindromic date:  2090-09-02
a palindromic date:  2101-10-12
a palindromic date:  2110-01-12
a palindromic date:  2111-11-12
a palindromic date:  2120-02-12
a palindromic date:  2121-12-12
a palindromic date:  2130-03-12
a palindromic date:  2140-04-12

Ring

load "stdlib.ring"

dt		= 0
num		= 0
limit	        = 15

? "First 15 palindromic dates:" + nl

while num < limit

	dt++
	dateStr  = adddays(date(),dt)
	newDate  = substr(dateStr,7,4) + substr(dateStr,4,2) + substr(dateStr,1,2)
	newDate2 = substr(dateStr,7,4) + "-" + substr(dateStr,4,2) + "-" + substr(dateStr,1,2)
	if ispalindrome(newDate)
                num++
		? newDate2 	
	ok
	if num > limit
		exit
	ok

end
Output:
First 15 palindromic dates:

2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

RPL

Works with: Halcyon Calc version 4.2.7
≪ DUP 100 MOD 4 400 IFTE MOD NOT ≫
‘LEAP?’ STO

≪ 100 + →STR 2 3 SUB ≫
‘→2STR’ STO

≪ STR→ → mm dd yy 
  ≪ mm 1 ≥ mm 12 ≤ AND 
     IF DUP 
     THEN 
        { 31 28 31 30 31 30 31 31 30 31 30 31 } 
        IF yy LEAP? THEN 2 29 PUT END 
        mm GET dd ≥ AND dd 1 ≥ AND 
     END 
≫ ≫
‘DTOK?’ STO

≪ →STR → year 
  ≪ year 4 DUP SUB year 3 DUP SUB + STR→ 
     year 2 DUP SUB year 1 DUP SUB + STR→ 
     IF DUP2 year DTOK? 
     THEN year "-" + ROT →2STR + "-" + SWAP →2STR + 
     ELSE DROP2 "" 
     END 
≫ ≫
‘PALDT’ STO
≪ { } 2023 
  WHILE OVER SIZE 15 < REPEAT 
     DUP PALDT 
     IF DUP "" ≠ THEN ROT SWAP + SWAP ELSE DROP END 
     1 + 
  END 
  DROP 
≫ 
EVAL
Output:
1: { "2030-03-02" "2040-04-02" "2050-05-02" "2060-06-02" "2070-07-02" 
     "2080-08-02" "2090-09-02" "2101-10-12" "2110-01-12" "2111-11-12" 
     "2120-02-12" "2121-12-12" "2130-03-12" "2140-04-12" "2150-05-12" }

Ruby

require 'date'

palindate = Enumerator.new do |yielder|
  ("2020"..).each do |y|
    m, d = y.reverse.scan(/../) # let the Y10K kids handle 5 digit years
    strings = [y, m, d]
    yielder << strings.join("-") if Date.valid_date?( *strings.map( &:to_i ) )
  end
end

puts palindate.take(15)
Output:
2020-02-02
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12

Rust

// [dependencies]
// chrono = "0.4"

fn is_palindrome(s: &str) -> bool {
    s.chars().rev().eq(s.chars())
}

fn main() {
    let mut date = chrono::Utc::today();
    let mut count = 0;
    while count < 15 {
        if is_palindrome(&date.format("%Y%m%d").to_string()) {
            println!("{}", date.format("%F"));
            count += 1;
        }
        date = date.succ();
    }
}
Output:

Output when program is run on 2020-07-13:

2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Sidef

Translation of: Ruby
var palindates = gather {
    for y in (2020 .. 9999) {
        var (m, d) = Str(y).flip.last(4).split(2)...
        with ([y,m,d].join('-')) {|t|
            take(t) if Date.valid(t, "%Y-%m-%d")
        }
    }
}

say "Count of palindromic dates [2020..9999]: #{palindates.len}"

for a,b in ([
    ["First 15:", palindates.head(15)],
    ["Last 15:",  palindates.tail(15)]
]) {
    say ("\n#{a}\n", b.slices(5).map { .join("   ") }.join("\n"))
}
Output:
Count of palindromic dates [2020..9999]: 285

First 15:
2020-02-02   2021-12-02   2030-03-02   2040-04-02   2050-05-02
2060-06-02   2070-07-02   2080-08-02   2090-09-02   2101-10-12
2110-01-12   2111-11-12   2120-02-12   2121-12-12   2130-03-12

Last 15:
9170-07-19   9180-08-19   9190-09-19   9201-10-29   9210-01-29
9211-11-29   9220-02-29   9221-12-29   9230-03-29   9240-04-29
9250-05-29   9260-06-29   9270-07-29   9280-08-29   9290-09-29

Swift

import Foundation

func isPalindrome(_ string: String) -> Bool {
    let chars = string.lazy
    return chars.elementsEqual(chars.reversed())
}

let format = DateFormatter()
format.dateFormat = "yyyyMMdd"

let outputFormat = DateFormatter()
outputFormat.dateFormat = "yyyy-MM-dd"

var count = 0
let limit = 15
let calendar = Calendar.current
var date = Date()

while count < limit {
    if isPalindrome(format.string(from: date)) {
        print(outputFormat.string(from: date))
        count += 1
    }
    date = calendar.date(byAdding: .day, value: 1, to: date)!
}
Output:

Output when executed on 2020-07-26:

2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

UNIX Shell

printf format, rev and date commands are the keys :

is_palyndrom_date() { date -d "$1" 1>/dev/null 2>&1 && echo "$1" ; }

for _H in {2..9}; do
 for _I in {0..9}; do
  for _J in {0..99}; do
   is_palyndrom_date ${_H}${_I}`printf "%02d%s" ${_J}`-`printf "%02d%s" ${_J} | rev`-`printf "%02d%s" ${_H}${_I} | rev`
  done
 done
done
Output:
2001-10-02
2010-01-02
2011-11-02
2020-02-02
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
...

VBA

Sub MainPalindromeDates()
Const FirstDate As String = "2020-02-02"
Const NumberOfDates As Integer = 15
Dim D As String, temp As String, Cpt As Integer
    temp = Format(DateAdd("d", 1, CDate(FirstDate)), "yyyy-mm-dd")
    Do
        D = Replace(temp, "-", "")
        If IsDatePalindrome(D) Then
            Debug.Print Left(D, 4) & "-" & Mid(D, 5, 2) & "-" & Right(D, 2)
            Cpt = Cpt + 1
        End If
        temp = Format(DateAdd("d", 1, CDate(temp)), "yyyy-mm-dd")
    Loop While Cpt < NumberOfDates
End Sub
Function IsDatePalindrome(strDate As String) As Boolean
    IsDatePalindrome = StrReverse(Left(strDate, 4)) = Right(strDate, 4)
End Function
Output:

The next 15 palindromic dates in yyyy-mm-dd format after 2020-02-02 are

2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Wren

Library: Wren-fmt
Library: Wren-date
import "/fmt" for Fmt
import "/date" for Date

var isPalDate = Fn.new { |date|
    date = date.format(Date.rawDate)
    return date == date[-1..0]
}

Date.default = Date.isoDate
System.print("The next 15 palindromic dates in yyyy-mm-dd format after 2020-02-02 are:")
var date = Date.new(2020, 2, 2)
var count = 0
while (count < 15) {
    date = date.addDays(1)
    if (isPalDate.call(date)) {
        System.print(date)
        count = count + 1
    }
}
Output:
The next 15 palindromic dates in yyyy-mm-dd format after 2020-02-02 are:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

XPL0

func Rev(N);
int  N;
[N:= N/10;
return rem(0)*10 + N;
];

proc NumOut(N);
int  N;
[if N < 10 then ChOut(0, ^0);
IntOut(0, N);
];

int C, Y, M, D, Q, R;
[C:= 0;
for Y:= 2021 to -1>>1 do
  for M:= 1 to 12 do
    for D:= 1 to 28 do
        [Q:= Y/100;
        R:= rem(0);
        if Q = Rev(D) and R = Rev(M) then
            [IntOut(0, Y);  ChOut(0, ^-);
            NumOut(M);  ChOut(0, ^-);
            NumOut(D);  CrLf(0);
            C:= C+1;
            if C >= 15 then return;
            ];
        ];
]
Output:
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12

Yabasic

Translation of: FreeBASIC
dateTest$ = ""
total = 0
print "Siguientes 15 fechas palindr¢micas al 2020-02-02:"
for anno = 2021 to 9999
    dateTest$ = ltrim$(str$(anno))
    for mes = 1 to 12
        if mes < 10 then dateTest$ = dateTest$ + "0" : fi
        dateTest$ = dateTest$ + ltrim$(str$(mes))
        for dia = 1 to 31
            if mes = 2 and dia > 28 then break : fi
            if (mes = 4 or mes = 6 or mes = 9 or mes = 11) and dia > 30 then break : fi
            if dia < 10 then dateTest$ = dateTest$ + "0" : fi
            dateTest$ = dateTest$ + ltrim$(str$(dia))
            for Pal = 1 to 4
                if mid$(dateTest$, Pal, 1) <> mid$(dateTest$, 9 - Pal, 1) then break : fi
            next Pal
            if Pal = 5 then 
                total = total + 1
                if total <= 15 then print left$(dateTest$,4),"-",mid$(dateTest$,5,2),"-",right$(dateTest$,2) : fi
            end if
            if total > 15 then break : break : break : fi
            dateTest$ = left$(dateTest$, 6)
        next dia
        dateTest$ = left$(dateTest$, 4)
    next mes
    dateTest$ = ""
next anno
end
Output:
Igual que la entrada de FreeBASIC.


zkl

TD,date,n := Time.Date, T(2020,02,02), 15;
while(n){
   ds:=TD.toYMDString(date.xplode()) - "-";
   if(ds==ds.reverse()){ n-=1; println(TD.toYMDString(date.xplode())); }
   date=TD.addYMD(date,0,0,1);
}
Output:
2020-02-02
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12