A compilation of documentation   { en , fr }

The GNU date command

Created on:
Last edited on:
Xavier Béguin
Version in French: La commande GNU date

If you use the command line interpreter on GNU/Linux, you might already know the numerous date and time formats the GNU command date can apply to print its information. The manual page date(1) references all the formats that can be specified using combinable sequences in an argument beginning with +.

Here is an example printing the current date and time in a provided format:

~$ date +"On %A, %-d %B %Y, at %R (day %j of the year)".
On Friday, 14 April 2023, at 17:20 (day 104 of the year).

For some sequences (like %A and %B above), date will use the localisation specified using the environment variable LC_TIME to print values in the designated language. This variable can be set to any localisation available on the system, which can be listed using the commande locale -a. If the specified locale does not exist, date will fall back to the english language.

On a system configured to use a specific localisation, a different localisation can occasionally be used by setting the environment variable LC_TIME for the command like so : LC_TIME=C date +%B (the localisation C represents the system defaults values, so here the english language will be used).

Printing a specific date

A lesser known functionality of date makes it a much more interesting command than expected. It is only discreetly mentioned in its manual page and can easily be overlooked: it is about the option -d that allows specifying a date to print, and especially specifying a date relatively to another date.

Printing a absolute date

This date or time can be specified in an absolute way, like 1914-07-28 06:00 or 28 July 1914 17:00 (only english names are recognised):

~$ date -d '1914-07-28 06:00'
Tue Jul 28 06:00:00 AST 1914
~$ date -d '28 July 1914 06:00:00'
Tue Jul 28 06:00:00 AST 1914

Printing a relative date

Yet what is particularly convenient is specirying an input date relatively to the current date and time or to a provided date and time. For example:

$ date -d 'yesterday'
Fri Oct  3 18:15:37 CEST 2014
$ date -d '2 days ago'
Thu Oct  2 18:15:42 CEST 2014
$ date -d 'last monday'
Mon 29 Sep 00:00:00 CEST 2014
$ date -d '1918-11-11 - 4 years'
mercredi 11 novembre 1914, 00:00:00 (UTC+0200)
Wed Nov 11 00:00:00 CEST 1914
$ date -d '2000-01-01 - 1 day'
Fri Dec 31 00:00:00 CEST 1999

Date input formats are referenced in the info page of date: run the command info date and follow the link Date input formats:: (place the cursor on it and press Enter). This page provides links to references of all accepted formats to specify the date to print; for information on relative dates, follow the link Relative items in date strings:: from this page.

Subtleties of the expression “last month

Be careful about some subtleties in the use of relative dates: as mentioned in the documentation, the term last month really represents - 30 days. Be watchful when using it with the last day of a month as reference:

~$ date -d "2014-10-31 last month"
Wed Oct  1 00:00:00 CEST 2014

To get the name of the last month, it is best to use a less problematic day of the month, for example the 15th. This can be achieved by using two nested calls to date: the first will construct the date of the 15th of the current month and the second the name of the last month:

$ date -d "$(date "+%Y-%m-15") last month" +%B

Specifying a time zone for dates in input or output

Time zone for the date to be printed

As a complement, note that, like many commands, to obtain the time from another time zone, you can simply set the environment variable TZ before calling date.

Thus, to know the current time in Singapore, you could use the following command:

$ TZ="Asia/Singapore" date
Sun Oct 15 00:37:00 +08 2014

Files providing information about time zones corresponding to cities and localities specified by TZ are stored in the directory /usr/share/zoneinfo (at least on Debian). To get an idea of all available city files, use the command:

find /usr/share/zoneinfo -printf "%P\n"

To get the time for the zone UTC-8 or GMT-8 (it seems that, in this case, GMT is a substitute for UTC), you also could use:

~$ TZ="Etc/GMT-8" date +"%A, %-d %B %Y, %T %z"
Sunday, 5 October 2014, 00:37:00 +0800

This is not an error, you indeed have to specify the file Etc/GMT-8 to get the time zone for GMT+8. This is a confusing notation inherited from the POSIX standard. Debian incidentally has the bug #540305 on this topic (open since 2009…).

Time zone for the input date

It is also possible to specify the time zone for the date we specify as input using the option -d.

For example, we will seek to know what was the time in Hong-Kong when it was 18:45 on the 4 October 2014 in Port-au-Prince (in Haïti):

  • if we know that Port-au-Prince used the time zone UTC-4 on october 2014 (as summer time), we can add the time zone specifier -0400 in the input date:
    ~$ TZ="Asia/Hong_Kong" date -d '2014-10-04 18:45-0400'
    Sun Oct  5 06:45:00 HKT 2014
  • but if we don't know that time zone was in use in Port-au-Prince on this day, we can specify the place using the variable TZ here as well in the argument for the option -d:
    ~$ TZ="Asia/Hong_Kong" date -d 'TZ="America/Port-au-Prince" 2014-10-04 18:45'
    Sun Oct  5 06:45:00 HKT 2014