Just use date
and trusty seconds:
As you rightly point out, a lot of the details about the underlying computation are hidden if you rely on English time arithmetic. E.g. -d yesterday
, and -d 1 day ago
will have different behaviour.
Instead, you can reliably depend on the (precisely documented) seconds since the unix epoch UTC, and bash arithmetic to obtain the moment you want:
date -d @$(( $(date +"%s") - 24*3600)) +"%Y-%m-%d"
This was pointed out in another answer. This form is more portable across platforms with different date
command line flags, is language-independent (e.g. "yesterday" vs "hier" in French locale), and frankly (in the long-term) will be easier to remember, because well, you know it already. You might otherwise keep asking yourself: "Was it -d 2 hours ago
or -d 2 hour ago
again?" or "Is it -d yesterday
or -d 1 day ago
that I want?"). The only tricky bit here is the @
.
Armed with bash and nothing else:
Bash solely on bash, you can also get yesterday's time, via the printf builtin:
%(datefmt)T
causes printf to output the date-time string resulting from using
datefmt as a format string for strftime(3). The corresponding argu‐
ment is an integer representing the number of seconds since the
epoch. Two special argument values may be used: -1 represents the
current time, and -2 represents the time the shell was invoked.
If no argument is specified, conversion behaves as if -1 had
been given.
This is an exception to the usual printf behavior.
So,
# inner printf gets you the current unix time in seconds
# outer printf spits it out according to the format
printf "%(%Y-%m-%d)T\n" $(( $(printf "%(%s)T" -1) - 24*3600 ))
or, equivalently with a temp variable (outer subshell optional, but keeps environment vars clean).
(
now=$(printf "%(%s)T" -1);
printf "%(%Y-%m-%d)T\n" $((now - 24*3600));
)
Note: despite the manpage stating that no argument to the %()T
formatter will assume a default -1
, i seem to get a 0 instead (thank you, bash manual version 4.3.48)