Skip to content

Instantly share code, notes, and snippets.

@hackerb9
Created December 9, 2017 11:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hackerb9/08645afe0bb211f98c421049df53fdac to your computer and use it in GitHub Desktop.
Save hackerb9/08645afe0bb211f98c421049df53fdac to your computer and use it in GitHub Desktop.
Bourne shell functions to show informal English time spans
# Some handy informal duration functions in Bourne shell (bash is fine, too).
# duration(): given seconds, returns commonsense equivalent duration.
# ago(): given seconds from epoch, compares to current time.
# howlongago(): show how long ago a file or subdir was last modified.
# given a file, shows how long ago that file was updated.
# given a directory, recursively searches for most
# recently changed FILE (not directory)
# given no argument, searches the current working directory.
# Examples:
#
# $ howlongago /etc/passwd
# Last updated 3 months, 15 weeks ago
#
# $ howlongago /var/www # searches recursively for most recent file
# Last updated 1 day, 0 hours ago
#
# $ howlongago # no argument checks current working directory
# Last updated 5 minutes, 57 seconds ago
#
# $ duration $((10**9)) # how long is a billion seconds?
# 31 years
#
# $ ago 0 # How long ago was the Unix Epoch?
# 60 years ago
#
# $ date +%s
# 1912817946 # Current number of seconds since the Epoch
#
# $ ago $(date +%s) # Of course, now is always now.
# just now
#
# # "ago" isn't just for the past
# $ ago $(date --date='next tuesday' +%s)
# 2 days, 20 hours from now
#
# # how long until R's birthday?
# $ ago $(date -d 'feb 11 next year' +%s)
# 2 months, 9 weeks from now
duration() {
# Input number of seconds, print informal duration in English.
# Shows two units of precision. (E.g., hours and minutes).
# Inaccuracies that probably don't matter:
# 1. Always rounds *down*.
# E.g. 1 hour, 59 minutes, 59 seconds => 1 hour, 59 minutes
# 2. A month is precisely 30 days. This is, of course, not quite true.
# 3. Similarly, a year is exactly 364 days.
local s=$1; local m=$((s / 60)); local h=$((m / 60))
local d=$((h / 24)); local w=$((d / 7)); local M=$((d / 30))
local y=$((d / 364))
if [ $s -lt 60 ]; then
span="$s second`s $s`"
elif [ $s -lt $((60*60)) ]; then
s=$((s%60))
span="$m minute`s $m`, $s second`s $s`"
elif [ $s -lt $((60*60*24)) ]; then
m=$((m%60))
span="$h hour`s $h`, $m minute`s $m`"
elif [ $s -lt $((60*60*24*7)) ]; then
h=$((h%24))
span="$d day`s $d`, $h hour`s $h`"
elif [ $s -lt $((60*60*24*30)) ]; then
d=$((d%7))
span="$w week`s $w`, $d day`s $d`"
elif [ $s -lt $((60*60*24*364)) ]; then
w=$((w%30))
span="$M month`s $M`, $w week`s $w`"
elif [ $s -lt $((60*60*24*364*10)) ]; then
M=$((M%12))
span="$y year`s $y`, $M month`s $M`"
else
span="$y year`s $y`" # Stopping counting months after a decade
fi
echo "$span"
}
ago() {
# Given a date (in seconds since The Epoch), print how long ago
# that was from now, in informal English.
local now=$(date +%s)
local s=$((now - $1))
if [ $s -eq 0 ]; then
echo "just now"
elif [ $s -gt 0 ]; then
echo "$(duration $s) ago"
else
s=$((-s))
echo "$(duration $s) from now"
fi
}
howlongago() {
# Given a directory or filename (or nothing for cwd), print how
# recently it was last modified in informal English.
# Note: Recursively searches directories for all files and reports
# on the one most recently updated. Directories themselves are
# *not* considered for comparison since they get modified by simple
# things like renaming or copying a file.
if [ -z "$1" ]; then
dir="."
else
dir="$1"
fi
local mostrecent=$(find "$dir" -type f -printf '%T@\n' | cut -d. -f1 | sort -n | tail -n1)
if [ -z "$mostrecent" ]; then
echo "No files found"
return
fi
echo "Last updated $(ago $mostrecent)"
}
s() {
if [ $1 -ne 1 ]; then echo -n "s"; fi
}
# TODO
# Maybe consider adding support for something larger than "years".
#
# Decades don't work since nobody talks about "4 decades and 7 years".
# We could use "score", for twenty years, but that's just weird.
# In English, what happens is people start rounding to the nearest
# decade at some point, as in: "over 130 years ago". Perhaps, I
# should start after a century?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment