]> Savannah Git Hosting - gnulib.git/commitdiff
parse-datetime: add debug warning about date arithmetic
authorAssaf Gordon <assafgordon@gmail.com>
Thu, 5 Jan 2017 04:11:33 +0000 (23:11 -0500)
committerAssaf Gordon <assafgordon@gmail.com>
Thu, 5 Jan 2017 05:08:06 +0000 (00:08 -0500)
Date arithmetic are done directly on the fields of 'struct tm',
which can result in invalid dates. Normalization with 'mktime(3)'
will then produce a different date - which might cause unexpected results.

Examples:
  '2016-10-31 - 1 month' => 2016-09-31 normalized to 2016-10-01.
  '2016-02-29 + 1 year'  => 2017-02-29 normalized to 2017-03-01.

Note that date normalization is not inherently wrong and not rejected,
as it has legitimate uses:
  '2016-12-29 + 5 days' => 2016-12-34 noramlized to 2017-01-03.

If the user asked to adjust months but 'mday' changed,
or user asked to adjust years but 'month' changed - warn about it.

    $ ./src/date --debug -d '2016-10-31 - 1 month'
    ...
    date: warning: when adding relative months/years, \
                   it is recommended to specify the 15th of the month
    ...
    date: warning: month/year adjustment resulted in shifted dates:
    date:      adjusted Y M D: 2016 09 31
    date:    normalized Y M D: 2010 10 01
    ...

* lib/parse-datetime.y (parse_datetime2): Detect such cases and print
a warning message. Improve recommendation of when to use 15 of the month
or noon for date arithmetic.

ChangeLog
lib/parse-datetime.y

index 7b2cb1de6e7b07957a3776b58e0effca72ea7c17..5753becf6f1f36b0ba3defbf42e21884be4518c6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,31 @@
 2017-01-04  Assaf Gordon <assafgordon@gmail.com>
 
+       parse-datetime: add debug warning about date arithmetic
+       Date arithmetic are done directly on the fields of 'struct tm',
+       which can result in invalid dates. Normalization with 'mktime(3)'
+       will then produce a different date - which might cause unexpected
+       results.
+       Examples:
+         '2016-10-31 - 1 month' => 2016-09-31 normalized to 2016-10-01.
+         '2016-02-29 + 1 year'  => 2017-02-29 normalized to 2017-03-01.
+       Note that date normalization is not inherently wrong and not rejected,
+       as it has legitimate uses:
+         '2016-12-29 + 5 days' => 2016-12-34 noramlized to 2017-01-03.
+       If the user asked to adjust months but 'mday' changed,
+       or user asked to adjust years but 'month' changed - warn about it.
+           $ ./src/date --debug -d '2016-10-31 - 1 month'
+           ...
+           date: warning: when adding relative months/years, \
+                          it is recommended to specify the 15th of the month
+           ...
+           date: warning: month/year adjustment resulted in shifted dates:
+           date:      adjusted Y M D: 2016 09 31
+           date:    normalized Y M D: 2010 10 01
+           ...
+       * lib/parse-datetime.y (parse_datetime2): Detect such cases and print
+       a warning message. Improve recommendation of when to use 15 of the
+       month or noon for date arithmetic.
+
        parse-datetime: fix debug message of relative part after timezone
        Relative part (e.g '+8 days') after a timezone string was not
        reported (was only reported after a timezone number). Due to the
index 719611323212dce95dbe99f203af310708727eb1..2e0a6096e4733d94028907e9fc255dddf03e39b7 100644 (file)
@@ -2090,12 +2090,12 @@ parse_datetime2 (struct timespec *result, char const *p,
         {
           if (pc.parse_datetime_debug)
             {
-              if ((pc.rel.year != 0 || pc.rel.month !=0) && tm.tm_mday==1)
+              if ((pc.rel.year != 0 || pc.rel.month !=0) && tm.tm_mday!=15)
                 dbg_printf (_("warning: when adding relative months/years, " \
                               "it is recommended to specify the 15th of the " \
                               "months\n"));
 
-              if (pc.rel.day != 0 && tm.tm_hour==0)
+              if (pc.rel.day != 0 && tm.tm_hour!=12)
                 dbg_printf (_("warning: when adding relative days, "    \
                               "it is recommended to specify 12:00pm\n"));
             }
@@ -2140,6 +2140,30 @@ parse_datetime2 (struct timespec *result, char const *p,
               dbg_printf (_("    new date/time = '%s'\n"),
                           debug_strfdatetime (&tm, &pc, dbg_tm,
                                               sizeof (dbg_tm)));
+
+              /* warn if the user did not ask to adjust days but mday changed,
+                 or
+                 user did not ask to adjust months/days but the month changed.
+
+                 Example for first case:
+                 2016-05-31 + 1 month => 2016-06-31 => 2016-07-01.
+                 User asked to adjust month, but the day changed from 31 to 01.
+
+                 Example for second case:
+                 2016-02-29 + 1 year => 2017-02-29 => 2017-03-01.
+                 User asked to adjust year, but the month changed from 02 to 03.
+              */
+              if (((pc.rel.day==0) && (tm.tm_mday != day))
+                  || ((pc.rel.day==0) && (pc.rel.month==0)
+                      && (tm.tm_mon != month)))
+                {
+                  dbg_printf (_("warning: month/year adjustment resulted in "\
+                                "shifted dates:\n"));
+                  dbg_printf (_("     adjusted Y M D: %04d %02d %02d\n"),
+                              year+1900, month+1, day);
+                  dbg_printf (_("   normalized Y M D: %04d %02d %02d\n"),
+                              tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
+                }
             }
 
         }