ISO 8601 and Date Arithmetic on the Command-Line

January 15, 2018

Why?

ISO 8601 Format

When you use date, you might not realize its full potential:

$ date
Mon Jan 15 18:43:31 PST 2018

it’s better if you provide a format:

$ date +%Y-%m-%d                  # iso8601, of course
2018-01-15

$ date +%F                        # same: iso8601 has its own short format
2018-01-15

Check man date for all the formats you need. But why wouldn’t you use ISO 8601?

Specify an Absolute Date

You can specify a date to format with -d, it recognizes a bunch of formats:

$ date +%F -d 2018-02-25          # silly: iso8601 to iso8601...
2018-02-25

$ date +%F -d "February 25 2018"  # full date
2018-02-25

$ date +%F -d "Feb 25 2018"       # short month
2018-02-25

$ date +%F -d "Feb 25"            # missing year, current year implied
2018-02-25

Specify a Relative Date

The -d flag also accepts relative dates:

$ date +%F -d "next Saturday"
2018-01-20

$ date +%F -d "next Sat"          # short day name
2018-01-20

$ date +%F -d "3 sat"             # 3 Saturdays from today
2018-02-03

$ date +%F -d "2 months"
2018-03-15

$ date +%F -d "3 weeks sat"       # Saturday after 3 weeks
2018-02-10

$ date +%F -d "last month"
2017-12-15

$ date +%F -d "-5 days"           # also: "5 days ago"
2018-01-10

The documentation says:

There is support for units (in singular and plural):

Date Arithmetic!

Yes, you can combine both absolute and relative dates:

$ date +%F -d "today + 3 days"
2018-01-18

$ date +%F -d "+ 3 days"          # shorter
2018-01-18

$ date +%F -d "3 days"            # shorter still
2018-01-18

$ date +%F -d "sep 1 - 3 weeks"
2018-08-11

$ date +%F -d "5 days - 3 weeks"
2017-12-30

Some of these are useful, others not so much… it depends what you need.

Think about your edge cases carefully:

$ date +%F -d "jan 27 + 1 month"
2018-02-27

$ date +%F -d "jan 28 + 1 month"
2018-02-28

$ date +%F -d "jan 29 + 1 month"  # careful!
2018-03-01

$ date +%F -d "feb 1 + 1 month"   # same...
2018-03-01

$ date +%F -d "jan 30 + 1 month"  # careful!
2018-03-02

$ date +%F -d "jan 31 + 1 month"  # careful!
2018-03-03

This page (bottom) discusses this gotcha and possible workarounds.

The subpages of Date input formats contain all the details from above and more… For example, I didn’t even try to discuss times, timezones and all their terrifying complexity.

My iso8601 Helper

Because I use ISO 8601 dates in a bunch of command-line contexts, I wrote a helper. Dump the script (call it iso8601) in your PATH:

#!/bin/bash

date +%F -d "$*"

The $* sequence means you don’t need to (but still can) quote your inputs:

$ iso8601
2018-01-15

$ iso8601 3 days
2018-01-18

$ iso8601 mar 15
2018-03-15

$ iso8601 jun 6 + 3 weeks
2018-06-27

$ iso8601 "jun 6 + 3 weeks"       # use quotes, if you want...
2018-06-27

I use this script mainly from inside Vim. I type !!iso8601 <bla bla> on a blank line to insert a date.

Discuss on Twitter