Subject: Re: bug#12772: date : Bug in handling human readable dates

From: Bob Proulx <[email-masked]>
Date: Wed, 31 Oct 2012 13:42:08 -0600

tag 12772 + notabug moreinfo
thanks

Guido Ackermann wrote:
> today i discovered a bug in the programm "date" handling human
> readable timeformats.

Thank you for the bug report.  And also thank you very much for
including the version you are using.  However you are tripping over a
common misconception about date.

> # export LC_ALL="C" ;date
> Wed Oct 31 10:57:06 CET 2012

In addition to LC_ALL please tell us what timezone you are using.  The
timezone string is ambiguous and CET may not be unique.  Better is to
use the -R format to get a standard unambiguous format.  Best is to
use UTC which avoids all of those issues.  You can do both on the
command without 'export'.  Using 'env' is the canonical method across
all shells.  For example:

  $ env LC_ALL=C TZ=Europe/Berlin date -R

> # export LC_ALL="C" ;date -d"last month"
> Mon Oct  1 11:57:23 CEST 2012

  $ env LC_ALL=C TZ=Europe/Berlin date -R -d "last month"
  Mon, 01 Oct 2012 21:36:34 +0200

> # export LC_ALL="C" ;date -d"next month"
> Sat Dec  1 10:57:35 CET 2012

  $ env LC_ALL=C TZ=Europe/Berlin date -R -d "next month"
  Sat, 01 Dec 2012 20:35:55 +0100

> While aktual monthh is still Oct, previous month is shown as Oct
> too, and next month is shown as Dec.
> Correctly "last month" should be Sep. "next month" should be Nov. 

Yes.  However this behavior is documented.  See the manual for the
full documentation.  Here are some sections from it:

     The unit of time displacement may be selected by the string `year'
  or `month' for moving by whole years or months.  These are fuzzy units,
  as years and months are not all of equal duration.  More precise units
  are `fortnight' which is worth 14 days, `week' worth 7 days, `day'
  worth 24 hours, `hour' worth 60 minutes, `minute' or `min' worth 60
  seconds, and `second' or `sec' worth one second.  An `s' suffix on
  these units is accepted and ignored.
  ...
     The fuzz in units can cause problems with relative items.  For
  example, `2003-07-31 -1 month' might evaluate to 2003-07-01, because
  2003-06-31 is an invalid date.  To determine the previous month more
  reliably, you can ask for the month before the 15th of the current
  month.  For example:

       $ date -R
       Thu, 31 Jul 2003 13:02:39 -0700
       $ date --date='-1 month' +'Last month was %B?'
       Last month was July?
       $ date --date="$(date +%Y-%m-15) -1 month" +'Last month was %B!'
       Last month was June!

     Also, take care when manipulating dates around clock changes such as
  daylight saving leaps.  In a few cases these have added or subtracted
  as much as 24 hours from the clock, so it is often wise to adopt
  universal time by setting the `TZ' environment variable to `UTC0'
  before embarking on calendrical calculations.

Please also see the FAQ where this issue is discussed at some length.

  http://www.gnu.org/software/coreutils/faq/#The-date-command-is-not-working-right_002e

Does that sufficiently answer your issue?

Bob