From: Gabriel <[email protected]>

* doc/parse-datetime.texi: Document dd.mm.yy support.
* lib/parse-datetime.y: Add grammar for dd.mm.yy and dd.mm.,
and logic to distinguish from tUDECIMAL_NUMBER.
---
 ChangeLog               |  7 +++++++
 doc/parse-datetime.texi |  4 ++++
 lib/parse-datetime.y    | 34 ++++++++++++++++++++++++++++++++--
 3 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 338d1fb31d..756eaec307 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2026-02-08  Gabriel  <[email protected]>
+
+       parse-datetime: support dd.mm.yy format
+       * doc/parse-datetime.texi: Document dd.mm.yy support.
+       * lib/parse-datetime.y: Add grammar for dd.mm.yy and dd.mm.,
+       and logic to distinguish from tUDECIMAL_NUMBER.
+
 2026-02-08  Pádraig Brady  <[email protected]>
 
        cpu-supports: fix license in source headers
diff --git a/doc/parse-datetime.texi b/doc/parse-datetime.texi
index b97be4a813..bbf645ae9a 100644
--- a/doc/parse-datetime.texi
+++ b/doc/parse-datetime.texi
@@ -172,6 +172,7 @@ numerically or literally.  All these strings specify the 
same calendar date:
 22-11-14       # Assume 19xx for 69 through 99,
                # 20xx for 00 through 68 (not recommended).
 11/14/2022     # Common U.S. writing.
+14.11.2022     # Common European writing.
 14 November 2022
 14 Nov 2022    # Three-letter abbreviations always allowed.
 November 14, 2022
@@ -184,6 +185,7 @@ used, or the current year if none.  For example:
 
 @example
 11/14
+14.11.
 nov 14
 @end example
 
@@ -200,6 +202,8 @@ is added to it; otherwise, if @var{year} is less than 100,
 then 1900 is added to it.  The construct
 @samp{@var{month}/@var{day}/@var{year}}, popular in the United States,
 is accepted.  Also @samp{@var{month}/@var{day}}, omitting the year.
+Similarly, the construct @samp{@var{day}.@var{month}.@var{year}}, popular in
+Europe, and its short form @samp{@var{day}.@var{month}.} are accepted.
 
 @cindex month names in date strings
 @cindex abbreviations for months
diff --git a/lib/parse-datetime.y b/lib/parse-datetime.y
index 85a7a92cc0..33e0215541 100644
--- a/lib/parse-datetime.y
+++ b/lib/parse-datetime.y
@@ -224,6 +224,8 @@ typedef struct
   idx_t zones_seen;
   bool year_seen;
 
+  bool not_decimal;
+
 #ifdef GNULIB_PARSE_DATETIME2
   /* Print debugging output to stderr.  */
   bool parse_datetime_debug;
@@ -573,8 +575,8 @@ debug_print_relative_time (char const *item, parser_control 
const *pc)
 %parse-param { parser_control *pc }
 %lex-param { parser_control *pc }
 
-/* This grammar has 31 shift/reduce conflicts.  */
-%expect 31
+/* This grammar has 32 shift/reduce conflicts.  */
+%expect 32
 
 %union
 {
@@ -847,6 +849,19 @@ date:
             pc->year = $5;
           }
       }
+  | tUNUMBER '.' tUNUMBER '.'
+      {
+        /* E.g., 17.6.  */
+        pc->day = $1.value;
+        pc->month = $3.value;
+      }
+  | tUNUMBER '.' tUNUMBER '.' tUNUMBER
+      {
+        /* E.g., 17.6.1992  */
+        pc->day = $1.value;
+        pc->month = $3.value;
+        pc->year = $5;
+      }
   | tUNUMBER tMONTH tSNUMBER
       {
         /* E.g., 17-JUN-1992.  */
@@ -1460,8 +1475,15 @@ yylex (union YYSTYPE *lvalp, parser_control *pc)
 
           if ((c == '.' || c == ',') && c_isdigit (p[1]))
             {
+              /* We are at the second period in a DD.MM.YYYY date */
+              if (pc->not_decimal)
+                {
+                  pc->not_decimal = false;
+                  goto normal_value;
+                }
               time_t s = value;
               int digits;
+              char const *old_p = p;
 
               /* Accumulate fraction, to ns precision.  */
               p++;
@@ -1469,6 +1491,12 @@ yylex (union YYSTYPE *lvalp, parser_control *pc)
               for (digits = 2; digits <= LOG10_BILLION; digits++)
                 {
                   ns *= 10;
+                  /* Don't parse DD.MM.YYYY dates as a decimal  */
+                  if (*p == '.') {
+                    p = old_p;
+                    pc->not_decimal = true;
+                    goto normal_value;
+                  }
                   if (c_isdigit (*p))
                     ns += *p++ - '0';
                 }
@@ -1501,6 +1529,7 @@ yylex (union YYSTYPE *lvalp, parser_control *pc)
             }
           else
             {
+             normal_value:
               lvalp->textintval.negative = sign < 0;
               lvalp->textintval.value = value;
               lvalp->textintval.digits = p - pc->input;
@@ -1851,6 +1880,7 @@ parse_datetime_body (struct timespec *result, char const 
*p,
   pc.dsts_seen = 0;
   pc.zones_seen = 0;
   pc.year_seen = false;
+  pc.not_decimal = false;
   pc.debug_dates_seen = false;
   pc.debug_days_seen = false;
   pc.debug_times_seen = false;
-- 
2.52.0


Reply via email to