As part of using shell scripts to generate Prometheus metrics, and also sometimes wanting to interact with Prometheus's API through the command line (cf), I've wound up getting deeper into the date command than I usually do.

(I've done some things with GNU date before, such as using ' date -d ', including for working out Linux kernel timestamps, something which is now mostly obsolete since ' dmesg -T ' will do that for you.)

If you have a timestamp of seconds since the epoch and want to convert it to a date, the GNU Date manpage itself will tell you about the '@<timestamp>' date format that it accepts as input:

date --date @2147483647

If you have something, like Prometheus' web interface, that requires input in UTC time, you can add --utc to see that instead of local time:

date -d @1556398606 --utc

By extension you can convert between local time and UTC time, for instance if you have logs in local time and need to plug their time into Prometheus in UTC. However, there is a gotcha; you may need to explicitly specify your timezone, even if it's not in the normal timestamp. So:

date -d 'Apr 26 08:24:30 EDT' --utc

To get the current time as seconds since the epoch, the format specifier is ' %s ':

date +%s

If you want to use timestamps from date to compute how long something took (for instance, generating metrics in a shell script), GNU date will give you nanoseconds as well with the ' %N ' format:

stime="$(date +%s.%N)" [...] etime="$(date +%s.%N)" dur="$(echo "$etime - $stime" | bc)"

The FreeBSD version of date has most of these features if you look through its manpage and the strftime(3) manpage, but it doesn't seem to be able to output the current time in any higher precision than the second. Rough equivalences are:

date -r 2147483647 date -r 1556398606 -u date +%s

There doesn't seem to be an easy way to convert a time string into UTC time output from what I can see (but perhaps I'm missing something). On the FreeBSD machine I have access to, the following outputs local time, not UTC time:

date -j -f '%b %d %T %Z' 'Apr 26 08:24:30 EDT' -u

You can do it in two steps, by converting the time string to a timestamp and then using ' date -r <..> -u ', but that's kind of annoying. You also have to specify the time string's format instead of letting GNU date's superintelligence work it out for you (hopefully correctly). If I had to do this on a FreeBSD machine, I would write some shell scripts, and then shortly they might turn into Perl programs or something so that they'd be smarter and do everything in one step. Also, a Perl, Python, C, or Go program would definitely be required if I needed timestamps with sub-second precision.

(Or one could just compile GNU date.)

(This is the kind of entry where I write things down for my future reference, since I keep digging them out of my older scripts and sometimes taking shortcuts.)