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
{
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"));
}
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);
+ }
}
}