Last active
December 21, 2015 05:19
-
-
Save robjwells/6256540 to your computer and use it in GitHub Desktop.
days - print the number of days between now and a given date
This file contains 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
#!/usr/local/bin/python3 | |
"""\ | |
Days | |
Calculate the number of days between a date and today or another date | |
Usage: | |
days <date> [<second_date> --format=<fmt>] | |
Options: | |
-f <fmt>, --format=<fmt> A strptime format string | |
[default: %Y-%m-%d] | |
""" | |
import sys | |
from docopt import docopt | |
from datetime import datetime | |
def parse_date(date_string, date_format): | |
"""datetime.strptime wrapper which exits on error | |
Attempt to parse date_string with date_format, both of which are | |
given by the user. On error, print the reason to stderror and exit | |
""" | |
try: | |
date = datetime.strptime(date_string, date_format) | |
except ValueError as error: | |
sys.exit(error) | |
else: | |
return date | |
args = docopt(__doc__) | |
if args['<second_date>']: | |
start_date = parse_date(args['<second_date>'], args['--format']) | |
else: | |
start_date = datetime.today() | |
target_date = parse_date(args['<date>'], args['--format']) | |
difference = (target_date.date() - start_date.date()).days | |
# .date() used to zero the time, otherwise you get odd results | |
if difference == 0 and not args['<second_date>']: | |
print("That's today!") | |
else: | |
days = 'day' if difference in [1, -1] else 'days' | |
message = '{} {} '.format(abs(difference), days) | |
if args['<second_date>']: | |
message += 'apart' | |
else: | |
message += ('ago' if difference < 0 else 'ahead') | |
print(message) |
This file contains 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
#!/bin/bash | |
# Assign first argument or stdin to $DATE | |
if [ -t 0 ]; then | |
DATE=$1 | |
else | |
read DATE | |
fi | |
if [ "$DATE" == "" ]; then | |
# Print usage message if no date is supplied | |
echo "Usage: $(basename $0) YYYY-MM-DD" | |
echo " prints number of days until or since the given date" | |
exit 64 | |
fi | |
# Exit if $DATE is not in ISO format | |
echo $DATE | egrep "[0-9]{4}-[0-9]{2}-[0-9]{2}" > /dev/null | |
if [ $? -ne 0 ]; then | |
echo "Abort: your date is not in YYYY-MM-DD format" | |
exit 65 | |
fi | |
THEN=$(date -jf %Y-%m-%d $DATE +%s) | |
NOW=$(date -j +%s) | |
DAYS=$(bc <<< "($THEN - $NOW) / 86400") | |
if [ $DAYS -eq 0 ]; then | |
echo "That's today!" | |
exit 0 | |
fi | |
MSG="$DAYS day" | |
if [ $DAYS -ne 1 ] && [ $DAYS -ne -1 ]; then | |
# Plural if number of days is not 1 and not -1 | |
MSG="${MSG}s" | |
fi | |
if [ $DAYS -lt 0 ]; then | |
# Trim sign if a negative number | |
echo $(cut -c 2- <<< $MSG) ago | |
else | |
echo $MSG ahead | |
fi | |
exit 0 |
@crmdgn (Sorry, only just seen your comment — no notifications for gists.)
Days are the largest unit stored by Python's datetime.timedelta objects (see line 40), and once you start dealing in months and years you've got to consider that they vary in length. It is possible, of course, but would require some thought to provide an answer that uses units larger than a week. At that point you're in the realm of true calendrical calculations as opposed to just subtracting one integer from another.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is handy. Is there a way to format the output in larger units, if it's a date in the far future? So, maybe,
X years, Y months, Z days ahead
?