38

The date command doesn't offer such thing, which is kind of sad since RFC-3339 is the modern, widespread, sane format used everywhere (except in email which is neither modern nor sane).

My timezone offset is currently -08:00 so the simplest form of this command should print the current time as 2013-09-05T14:58:33.102-08:00.

  • Which standard (s) are you interested in? – Stéphane Chazelas Mar 19 '14 at 21:54
  • I personally am fine with GNU but in the grand scheme of things it really should be broader than that. It should also come with a reasonable default (short option, millisecond precision) and have a way to specify the subsecond precision (number of digits other than 0 or 9). – Martin Jambon Mar 19 '14 at 22:37
  • 1
    It's not a sane format: the total absence of whitespace makes it unnecessarily hard for humans to read. You should use the slight variation 2013-09-05 14:58:33.102 -0800 except when there is some reason why spaces must not be used at all. – zwol Mar 20 '14 at 01:26
  • 2
    I was comparing it to the mail date format (RFC 822, 2822) which is hard to read for both humans and machines. – Martin Jambon Mar 20 '14 at 01:31

7 Answers7

49

It seems like you can do several formats using the switch to the GNU implementation of date (version 5.90 or above), --rfc3339=.

Examples

$ date --rfc-3339=date
2014-03-19

$ date --rfc-3339=seconds 2014-03-19 18:00:05-04:00

$ date --rfc-3339=ns 2014-03-19 18:00:08.179780629-04:00

If you want the T to be added, as a hack:

$ date --rfc-3339=seconds | sed 's/ /T/'
2014-03-19T18:35:03-04:00

If you want it in milliseconds:

$ date --rfc-3339=ns | sed 's/ /T/; s/\(\....\).*\([+-]\)/\1\2/g'
2014-03-19T18:42:52.362-04:00

References

slm
  • 369,824
  • 14
    These days, no hack is needed to get the 'T'. The --iso-8601' option accepts the same arguments as--rfc-3339`, and includes the 'T' in its output. – Ti Strga Mar 23 '16 at 18:41
  • BTW, RFC3339 requires uppercase T in expression. If it's missing, it's not standard (RFC3339) compliant. ISO8601 allows more variants, and more ambiguous and harder to parse and process. – Eonil Dec 13 '17 at 16:36
  • 1
    Sed part s/\(\....\).*-/\1-/g should be s/\(\....\).*\([+-]\)/\1\2/g to also work east of the Atlantic. – svante Sep 11 '19 at 12:01
  • 1
    @svante - thanks for the detail, fixed. – slm Sep 11 '19 at 12:09
  • 3
    @Eonil that is actually not correct, the RFC3339 states: NOTE: ISO 8601 defines date and time separated by "T". While RFC3339 allows you to use a space instead. Read https://www.ietf.org/rfc/rfc3339.txt Section 5.6 – rwenz3l Oct 08 '19 at 12:47
  • 2
    @rwenz3l My fault. I just read only ABNF part and missed the notes. Thanks for pointing it out! – Eonil Oct 09 '19 at 09:46
  • 1
    @Eonil No problem, it is quite confusing that they have extra prose contradicting the BNF. The prose also says you are allowed to use lowercase t and z instead of uppercase! – Lassi Dec 14 '19 at 13:42
19

With GNU date (5.90 or above):

$ TZ=America/Anchorage date '+%FT%T.%N%:z'
2014-03-19T14:29:31.041119357-08:00

Replace %N with %3N for milliseconds, %6N for micro-seconds...

AFAIK, none of the POSIX, Unix or LSB specifications specify any command that can display times with sub-second granularity, but the fractional part is optional in RFC 3339.

POSIX/Unix/LSB strftime supports %z to display the TZ offset as -0800, so the most portable you're probably going to get is:

 $ TZ=America/Anchorage perl -MPOSIX -le '$t = strftime "%Y-%m-%dT%T%z",
   localtime; $t =~ s/..$/:$&/; print $t'
 2014-03-19T14:30:23-08:00
19

You can also format time according to RFC3339 ( ISO8601 ) easier:

$ date -u +"%Y-%m-%dT%H:%M:%SZ"
2016-11-08T08:52:55Z

NOTE: This format is also used in the Label Schema Convention RC 1.0

  • 1
    That's not a valid RFC3339. Eran's answer of
    date +%Y-%m-%dT%T%z
    

    is correct and less characters. If you want in UTC pass -u flag, which will zero out the timezone offset.

    – briceburg Nov 14 '17 at 19:25
  • 1
    With the -u flag this answer is correct, right? – Lassi Dec 14 '19 at 15:41
  • 1
    @briceburg why is this not valid RFC3339? According to https://tools.ietf.org/html/rfc3339#section-5.6 it seems to be correct as far as I can tell. – voutasaurus Apr 27 '20 at 23:57
13

How about good old :

$ date +%Y-%m-%dT%T%z
2015-10-29T14:47:06+0200
9

GNU date has the ISO-8601 format built in - isn't that quite close or even idential to RFC-3339?

1065 % date --iso-8601=seconds
2014-03-19T16:51:16-0600
  • ISO-8601 allows different formattings of dates and times, but I think the OP is asking specifically for W3C Date format "Complete date plus hours, minutes, seconds and a decimal fraction of a second YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)" - W3C Date and Time Formats. – hakre Oct 13 '14 at 10:58
2
echo "Local date only:"
date '+%Y-%m-%d'
echo
echo "Local date and time:"
date '+%Y-%m-%dT%H:%M:%S%z' | sed 's@^.\{22\}@&:@'
echo
echo "UTC date and time:"
date -u '+%Y-%m-%dT%H:%M:%SZ'

These commands are POSIX-compatible, with the exception of the %z conversion specification. However, %z is widely supported and works the same way in Linux, MacOS, FreeBSD, OpenBSD, NetBSD, DragonFlyBSD, Solaris, Minix and Haiku. It also works with the tools in Busybox, Toybox and sbase (the suckless.org base system utilities). Since %z outputs the timezone offset in ±HHMM format, we need the sed pipe to add a colon and change it to ±HH:MM.

NOTE: The Heirloom project's date command has incompatible %z output: it does not print a + sign.

Lassi
  • 831
  • 6
  • 15
0

For UTC you can use.

date -u --rfc-3339=ns | sed -r 's/ /T/; s/\.([0-9]{3}).*/\.\1Z/'
Ajeet47
  • 101