Skip to Content

Terminally Geeky: Deadline reminders using Growl, sleepwatcher, and GNU date

When I have a large deadline looming, I like to keep track of how many days I have left.

I've tried Dashboard widgets, iPad apps and just about anything else you could think of, but they all have failed for one simple reason: they require me to check them. I can go days or weeks without triggering the Dashboard, and an iOS countdown app still requires that you check it. I could use something like Due app, but I really don't want something actively distracting me -- I want something passively reminding me. Nor do I want these cluttering up my iCal.

I found my solution by cobbling together several bits of free Unix utilities that are essential to any true geek's tool belt.

Preparation

First, make sure you have the GNU Coreutils installed. You could install them manually, but if you don't have them already, I suggest getting them either from MacPorts (sudo port install coreutils) or Rudix (if you're not familiar with Rudix, check out our previous coverage). We're going to be using the GNU version of 'date', which MacPorts puts in /opt/local/bin/gdate and Rudix installs to /usr/local/bin/date. Set the GNUDATE variable to the appropriate path below.

Second, you'll need SleepWatcher, which is another free program that will automatically run shell scripts whenever your computer goes to sleep or wakes up. Download the file and follow the instructions in the ReadMe.rtf to install it. (Note that you may need to create /usr/local/sbin/ before installing it: 'sudo mkdir /usr/local/sbin').

Third, you'll need 'growlnotify' from Growl. Download the regular Growl DMG, mount it and install the growlnotify.pkg from inside the 'Extras' folder.

OK, now all of that sounds complicated, but it shouldn't take you more than a few minutes, and once you install all the necessary pieces, you'll be ready to do other cool things with them in the future.

The Script

Now that we have all of the necessary pieces, we just need to put them to good use. Once you have SleepWatcher installed and working (don't forget about installing the launchd plist and loading it as instructed in the ReadMe.rtf), your personal 'wakeup' script will be kept at ~/.wakeup, and you'll need to add the following lines to it (the #!/bin/sh line should be the very first line of the file, and should only appear once).

#!/bin/sh

### Deadline Reminder
## if you installed coreutils using the Rudix installer, uncomment the next line
# GNUDATE=/usr/local/bin/date

## if you installed coreutils using MacPorts, uncomment the next line
# GNUDATE=/opt/local/bin/gdate

# March 1st is my deadline. Change '1 march' to your deadline!
DUEDATE=`$GNUDATE '+%j' --date '1 march'`

# today's date
TODAYDATE=`$GNUDATE '+%j'`

DAYSLEFT=`expr $DUEDATE - $TODAYDATE`

growlnotify -a "Scrivener" --sticky --message "$DAYSLEFT days left" "Thesis"

What it does

What the script does is very simple. Using GNU date, it calculates the day of the year (0-365 or 366 in a leap year) of your deadline. For example, March 1 is the 60th day of the year 2011 (31 days in January + 28 days in February), so if I did

gdate '+%j' --date '1 march 2011'

I would get

060

So, in the above script "$DUEDATE" gets set to 060 and then compared to "$TODAYDATE", which gets set to whatever day today is (for example, Feb 18 is 049). Then we use 'expr' to subtract $TODAYDATE (049) from $DUEDATE (060) and get 11 days remaining, which is put into the variable $DAYSLEFT.

Once the information is calculated, we have to display it to the user. That's where growlnotify comes in. I am writing my Thesis in Scrivener so I tell growlnotify: "Using Scrivener's app icon, show me an alert window telling me I have $DAYSLEFT days left. Make the title of the window "Thesis" and make the window 'sticky' meaning that it will not go away until I click on it.

You could leave --sticky off if you wanted the alert to go away automatically, but I want to have to acknowledge it.

Known Bugs/Limitations

Note that this script assumes that your deadline is in the current calendar year. If I tried to run this script on December 15, 2010 and my deadline wasn't until March 1, 2011, I would get -289 because the script doesn't take 'year' into consideration; it would be counting the days between March 1 (the 60th day of the year) and December 15 (the 349th day of the year).

Solving that problem will be, as Dr. Cupper (my Computer Science professor) used to say, "Left as an exercise for the reader."



Categories

How-tos OS X

When I have a large deadline looming, I like to keep track of how many days I have left. I've tried Dashboard widgets, iPad apps and just...
 

Add a Comment

*0 / 3000 Character Maximum Comment Moderation Enabled. Your comment will appear after it is cleared by an editor.

8 Comments

Filter by:
gajahduduk

Why not try OmniGrowl? It has long supported Growl alerts for to-dos with due dates of tomorrow and today. The newest version, released today, supports this kind of daily count down as well, up to 60 days out.

http://www.woodenbrain.com/blog.php?id=1665441572920722548

It is $12 shareware, but I think it's more than worth it. :)

Disclosure: I'm the developer.

February 24 2011 at 11:22 AM Report abuse rate up rate down Reply
GlennAC

I still like the ease of using iCal for it's alerts function. First, they popup without the app being active, and I can setup such alerts from the Calendar app on my iPhone which is usually what I have at hand when I need to set such alarms.

If I had to wait until I got back to my Mac to setup such alerts I'd have forgotten half of them.

February 19 2011 at 6:20 PM Report abuse rate up rate down Reply
Dean

Pookey. Forgot to encode my < and > symbols. Try this version:

----

#!/bin/sh

### Deadline Reminder

# usage:
# reminder.sh [date] <[title]> <[message]>
# where:
# [date] is a due date in YYYY-MM-DD format, e.g. 2011-03-30
# <[title]> is an optional title for the growl notification, e.g. "End of the World"
# <[message]> is an optional additional message for growl notification, e.g. "to get your affairs in order"

if [ "$#" == "0" ]; then
echo "usage: reminder.sh [YYYYMMDD] <[title]> <[message]>"
exit 1
fi

# due date from the command line
MYDUEDATE=$1
shift
# growl title from the command line
MYTITLE=$1
shift
# growl message from the command line
MYMESSAGE=$1

# set the default title if one was not on the command line
if [ "$MYTITLE" == "" ]; then
MYTITLE="Reminder"
fi

# deadline
DUESECS=`date -j -f"%Y-%m-%d" "$MYDUEDATE" +%s`

# today's date
TODAYSECS=`date +%s`

# delta in seconds
SECSLEFT=`expr $DUESECS - $TODAYSECS`

# integer divide by 86,400 - the number of seconds in a day
DAYSLEFT=`expr $SECSLEFT / 86400`

growlnotify --sticky --message "$DAYSLEFT days left $MYMESSAGE" "$MYTITLE"

February 19 2011 at 1:01 AM Report abuse rate up rate down Reply
1 reply to Dean's comment
TJ Luoma

Very nice! I had missed the -j flag for the default 'date' command. I still prefer the GNU date for its other options, but it's always nice to use the built-in tools when possible.

February 19 2011 at 1:19 AM Report abuse rate up rate down Reply
Dean

You can do the same thing with the built-in OS X 'date' command without installing GNU Coreutils. Here's a version that does that and adds more flexibility by moving the due date and other parms to the command line so you don't have to edit the script every time you need a new reminder:

----


#!/bin/sh

### Deadline Reminder

# usage:
# reminder.sh [date]
# where:
# [date] due date in YYYY-MM-DD format, e.g. "2011-03-30"
# optional title for the growl notification, e.g. "Thesis"
# optional message for growl notification, e.g. "to finish thesis"

if [ "$#" == "0" ]; then
echo "usage: reminder.sh [YYYYMMDD] "
exit 1
fi

# due date from the command line
MYDUEDATE=$1
shift
# growl title from the command line
MYTITLE=$1
shift
# growl message from the command line
MYMESSAGE=$1

# set the default title if one was not on the command line
if [ "$MYTITLE" == "" ]; then
MYTITLE="Reminder"
fi

# deadline
DUESECS=`date -j -f"%Y-%m-%d" "$MYDUEDATE" +%s`

# today's date
TODAYSECS=`date +%s`

# delta in seconds
SECSLEFT=`expr $DUESECS - $TODAYSECS`

# integer divide by 86,400 - the number of seconds in a day
DAYSLEFT=`expr $SECSLEFT / 86400`

growlnotify --sticky --message "$DAYSLEFT days left $MYMESSAGE" "$MYTITLE"

----

Example:

./reminder.sh 2011-05-21 "End of the World" "to either get your affairs in order or plan a post-apocalypse party"

February 19 2011 at 12:56 AM Report abuse rate up rate down Reply
gnicholls

You do have your iPhone synced to your Google Apps account right? Just create a calender for these things and turn off its display wherever you don't want clutter. Add events with the web interface.

February 18 2011 at 6:57 PM Report abuse rate up rate down Reply
CanadianMacFan

The following should work across year boundaries. The calculations are done using the number of seconds from the start of 1970.

----

#!/bin/sh

### Deadline Reminder
## if you installed coreutils using the Rudix installer, uncomment the next line
# GNUDATE=/usr/local/bin/date

## if you installed coreutils using MacPorts, uncomment the next line
# GNUDATE=/opt/local/bin/gdate

# March 1st is my deadline. Change '1 march' to your deadline!
DUESECS=`$GNUDATE '+%s' --date '1 march 2012'`

# today's date
TODAYSECS=`$GNUDATE '+%s'`

SECSLEFT=`expr $DUEDATE - $TODAYDATE`

# Divide by 86400 as there are that many seconds in a day.
DAYSLEFT=`expr $SECSLEFT / 86400`

growlnotify -a "Scrivener" --sticky --message "$DAYSLEFT days left" "Thesis"

February 18 2011 at 5:12 PM Report abuse rate up rate down Reply
1 reply to CanadianMacFan's comment
TJ Luoma

I *knew* I could trick someone into figuring this out for me :-)

Just kidding. Well, mostly… That was the same approach I was thinking of but didn't.

Thanks for sharing it!

February 18 2011 at 5:57 PM Report abuse rate up rate down Reply
Buy an ad here

Tweets

© 2012 AOL Inc. All Rights Reserved.