Dating myself

One of the things I like about TextExpander is the flexibility with which it can create date and time values. I used to think that some of that flexibility wasn’t available using the standard Unix/C strftime codes, but last week I learned I was wrong about that.

The date/time formatting feature of TextExpander that stood out for me was the ability to use single-digit values when the number was less than 10. For example, you can specify that month value not include a leading zero for January through September.

TextExpander dates

In the content area of the TextExpander window, this will show up as the code %1m, with the 1 indicating that it takes up just one space if it’s a single-digit value. There are similar codes for one-digit days, hours, minutes, and seconds. You can see all the codes near the end of the TextExpander FAQ. These codes are handy when you want to format a date in the standard American fashion. A snippet defined as %1m/%1d/%y will result in 7/2/12 if invoked today. You can, no doubt, think of other situations where you’d want to use this formatting.

If you look through the date/time formatting codes in the Python documentation, you’ll notice that there are no “1” versions. You can do

python:
from datetime import date
d = date.today()
print d.strftime("%m/%d/%y")

to get 07/02/12, but changing the last line to

python:
print d.strftime("%1m/%1d/%y")

results in 1m/1d/12 because %1m and %1d aren’t recognized as valid codes. There are, in fact, no codes mentioned in the documentation for creating single-digit versions of the day, month, hour, etc.

I used to think that single-digit values were impossible in Python without some after-the-fact fiddling. In my weathertext script, for example, I needed a date in the format 2 Jul 2012, with no leading zero for the day of the month. I did it this way:1

python:
today = datetime.datetime.now()
today = today.strftime("%d %b %Y")
today = re.sub(r'^0(\d)', r'\1', today)   # delete leading zero on day

I should have noticed this passage:

The full set of format codes supported varies across platforms, because Python calls the platform C library’s strftime() function, and platform variations are common.

The following is a list of all the format codes that the C standard (1989 version) requires, and these work on all platforms with a standard C implementation. Note that the 1999 version of the C standard added additional format codes.

If I had, I would have looked in the man page for strftime and found this:

%-*    GNU libc extension. Do not do any padding when performing numerical outputs.

I found this more or less by accident last week when I needed to use the date command and couldn’t remember which formatting codes I needed. When I saw it, I suspected it would apply to Python’s strftime, too.

It does. For the American-style date example,

python:
print d.strftime("%-m/%-d/%y")

gives 7/2/12, just what I want. This means I can simplify the weathertext code to

python:
today = datetime.datetime.now()
today = today.strftime("%-d %b %Y")

without any of that substitution nonsense.

I suppose using the hyphened versions of the date/time codes will make my scripts a little less portable, but since they come from the GNU version of libc, they should work on Linux, too. That’s portable enough for me.


  1. I’ve simplified the code a bit, but the basics are the same.