3

How to I get the GNU date command to interpret dates in the format 'dd/mm/yyyy', for example:

What I get:

$ date  -d '09/07/2016'
Wed, Sep  7, 2016 12:00:00 AM

What I want:

$ date  -d '09/07/2016'
Sat, Jul  9, 2016 12:00:00 AM

I've tried setting LC_ALL but to no avail.

4

Note that date -d is a GNU extension. The syntax it expects is fixed and independent from the locale. In particular, it does not use POSIX getdate() to parse the date (even though the interface GNU date uses used to be called getdate() as well).

Some builds of some versions of busybox also recognise a -d option, but the range of supported formats is narrower. In particular, it does not recognise mm/dd/YYYY. You can however pass a -D <strptime-format> option (thanks @BinaryZebra) to specify the format you like:

$ date -D %d/%m/%Y -d 01/10/2016
Sat Oct  1 00:00:00 BST 2016

AT&T (ast-open) date, since 1995, also supports a GNU-style -d option. That one does use POSIX getdate(). So with that date implementation, you can use the DATEMSK variable to change the way dates are parsed and since 1996, you can use the -p option to pass a strptime-style parsing format on the command line:

$ date --version
  version         date (AT&T Research) 2011-01-27
$ date -d 01/10/2016
Sun Jan 10 13:36:39 GMT 2016
$ date -d 01/10/2016 -p %d/%m/%Y
Sat Oct  1 13:36:51 BST 2016

AT&T ksh93's printf %T also uses a getdate()-compatible API and so can also be affected by the DATEMSK variable, so in ksh93, you can do:

$ DATEMSK=/dev/stdin <<< %d/%m/%Y printf '%T\n' 01/10/2016
Sat Oct  1 13:47:06 BST 2016

To parse a date portably in a zsh script, you can used the strftime builtin (after loading it) with the -r option:

$ zmodload zsh/datetime
$ strftime -s REPLY -r '%d/%m/%Y' 09/07/2016
$ strftime %c $REPLY
Sat 09 Jul 2016 00:00:00 BST

zsh's strftime -r uses POSIX strptime() to parse the string. As such, it is locale-dependant. In a French locale for instance, you can use strftime -r %d-%b-%Y 14-juillet-2016 to parse a French date.

Some strptime() implementations like GNU's still accept the English month/day names when in non-English locales, but not all (Solaris 11's one doesn't for instance). Something to bear in mind when parsing an English date in the user's locale.

Recent versions of bash also have a ksh-style printf '%(format)T', but that one has no time parsing capability.

For completeness, on BSDs, date accepts a -f <strptime-format> which you can use in combination with -j to reformat a date:

$ date -jf %d/%m/%Y 01/10/2016
Sat Oct  1 13:47:06 BST 2016
2

Using busybox date seems like the right choice:

$ busybox date -uD '%d/%m/%Y' -d '09/07/2016'
Sat Jul  9 00:00:00 UTC 2016

That works because busybox date accepts a format (-D) to read the date inside -d.

To make the command more reliable and to build exactly the format you ask for:

$ LC_ALL=C busybox date -uD '%d/%m/%Y' -d '09/07/2016' +'%a, %b %d, %Y %r'
Sat, Jul 09, 2016 12:00:00 AM

Busybox date command.

1

From info date

For numeric months, the ISO 8601 format YEAR-MONTH-DAY is allowed
When months are written literally, the calendar date may be given as any of the following:

 DAY MONTH YEAR
 DAY MONTH
 MONTH DAY YEAR
 DAY-MONTH-YEAR

So main rule

All these strings specify the same calendar date:

 1972-09-24     # ISO 8601.
 72-9-24        # Assume 19xx for 69 through 99,
                # 20xx for 00 through 68.
 72-09-24       # Leading zeros are ignored.
 9/24/72        # Common U.S. writing.
 24 September 1972
 24 Sept 72     # September has a special abbreviation.
 24 Sep 72      # Three-letter abbreviations always allowed.
 Sep 24, 1972
 24-sep-72
 24sep72

In the case you can use literal name of the month or rebuild date string prior to feed it to date

  1. IFS='/' read d m y <<<09/07/2016 ; echo "$m/$d/$y"
  2. sed -r 's|([^/]*)/([^/]*)|\2/\1|' <<<09/07/2016
  3. tr '/' '\n' <<<09/07/2016 | tac | tr '\n' '-'
0

Not the best one, but for completeness: The obvious solution is to reformat the source value:

$ d='09/07/2016'

$ date -d "${d:3:2}/${d:0:2}/${d:6}" +'%a, %b %e, %Y %r'
Sat, Jul  9, 2016 12:00:00 AM

If your locale include the correct format, just use:

$ date -d "${d:3:2}/${d:0:2}/${d:6}"
Sat, Jul  9, 2016 12:00:00 AM
-2

Use the format option:

date -d `date -d '09/07/2016' +"%d/%m/%Y"` +"%a, %b %-d, %Y 12:00:00 AM"
  • 3
    That breaks if the day is after the 12th of a month. (And is a horrible way of cheating) – Henrik supports the community Jul 15 '16 at 6:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.