Skip to content

Instantly share code, notes, and snippets.

@alexwlchan
Created December 22, 2014 20:36
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save alexwlchan/73933442112f5ae431cc to your computer and use it in GitHub Desktop.
Save alexwlchan/73933442112f5ae431cc to your computer and use it in GitHub Desktop.
Prints human-readable, friendly strings to measure elapsed time
#!/usr/bin/python
"""elapsed.py - a script for providing a human-readable string of how much time
has elapsed since a given date, implemented only using the standard library.
Modelled on the style of dates used on Stack Overflow posts.
"""
from datetime import datetime, timedelta
def print_date(date, incl_year=True, short_months=True):
"""Prints a datetime object as a full date, stripping off any leading
zeroes from the day (strftime() gives the day of the month as a zero-padded
decimal number).
"""
# %b/%B are the tokens for abbreviated/full names of months to strftime()
if short_months:
month_token = '%b'
else:
month_token = '%B'
# Get a string from strftime()
if incl_year:
date_str = date.strftime('%d ' + month_token + ' %Y')
else:
date_str = date.strftime('%d ' + month_token)
# There will only ever be at most one leading zero, so check for this and
# remove if necessary
if date_str[0] == '0':
date_str = date_str[1:]
return date_str
def elapsed_time_str(past_time, max_days=5, short_months=True):
"""Accepts a datetime object or a string in ISO 8601 format and returns a
human-readable string explaining when this time was.
The rules are as follows:
* If a time is within the last hour, return 'XX minutes'
* If a time is within the last 24 hours, return 'XX hours'
* If within the last 5 days, return 'XX days'
* If in the same year, print the date without the year
* If in a different year, print the date with the whole year
These can be configured as options.
"""
now_time = datetime.now()
#--------------------------------------------------------------------------
# If the user passes in a string, try to turn it into a datetime object
# before continuing
#--------------------------------------------------------------------------
if isinstance(past_time, str):
print "it's a string!"
try:
past_time = datetime.strptime(past_time, "%Y-%m-%dT%H:%M:%S.%fZ")
except ValueError:
raise ValueError("User supplied string %s is not in ISO 8601 "
"format." % past_time)
elif isinstance(past_time, datetime):
pass
else:
raise ValueError("User-supplied value %s is neither a datetime object "
"nor an ISO 8601 string." % past_time)
#--------------------------------------------------------------------------
# It doesn't make sense to measure time elapsed between now and a future
# date, so we'll just print the date
#--------------------------------------------------------------------------
if past_time > now_time:
incl_year = (past_time.year != now_time.year)
time_str = print_date(past_time,
incl_year=incl_year,
short_months=short_months)
#--------------------------------------------------------------------------
# Otherwise, start by getting the elapsed time as a datetime object
#--------------------------------------------------------------------------
else:
elapsed_time = now_time - past_time
# Check if the time is within the last minute
if elapsed_time < timedelta(seconds=60):
if elapsed_time.seconds == 1:
time_str = "a second ago"
else:
time_str = "%d secs ago" % elapsed_time.seconds
# Check if the time is within the last hour
elif elapsed_time < timedelta(seconds=60 * 60):
# We know that seconds > 60, so we can safely round down
minutes = elapsed_time.seconds / 60
if minutes == 1:
time_str = "a minute ago"
else:
time_str = "%d mins ago" % minutes
# Check if the time is within the last day
elif elapsed_time < timedelta(seconds=60 * 60 * 24 - 1):
# We know that it's at least an hour, so we can safely round down
hours = elapsed_time.seconds / (60 * 60)
if hours == 1:
time_str = "an hour ago"
else:
time_str = "%d hours ago" % hours
# Check if it's within the last N days, where N is a user-supplied
# argument
elif elapsed_time < timedelta(days=max_days):
if elapsed_time.days == 1:
time_str = "yesterday"
else:
time_str = "%d days ago" % elapsed_time.days
# If it's not within the last N days, then we're just going to print
# the date
else:
incl_year = (past_time.year != now_time.year)
time_str = print_date(past_time,
incl_year=incl_year,
short_months=short_months)
return time_str
def main():
"""Read a user-supplied string from stdin, and return an elapsed time
string.
"""
import sys
print elapsed_time_str(sys.stdin.read())
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment