Created
December 9, 2017 11:37
-
-
Save hackerb9/08645afe0bb211f98c421049df53fdac to your computer and use it in GitHub Desktop.
Bourne shell functions to show informal English time spans
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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