Recipe3.2.Finding Last Friday


Recipe 3.2. Finding Last Friday

Credit: Kent Johnson, Danny Yoo, Jonathan Gennick, Michael Wener

Problem

You want to find the date of last Friday (or today, if today is Friday) and print it in a specified format.

Solution

You can use the datetime module from Python's standard library to easily achieve this:

import datetime, calendar lastFriday = datetime.date.today( ) oneday = datetime.timedelta(days=1) while lastFriday.weekday( ) != calendar.FRIDAY:     lastFriday -= oneday print lastFriday.strftime('%A, %d-%b-%Y')  # emits, e.g.: Friday, 10-Dec-2004

Discussion

The handy little snippet of code in this recipe lets us find a previous weekday and print the properly formatted date, regardless of whether that weekday is in the same month, or even the same year. In this example, we're looking for the last Friday (or today, if today is Friday). Friday's integer representation is 4, but to avoid depending on this "magical number," we just import the Python Standard Library calendar module and rely instead on its calendar.FRIDAY attribute (which, sure enough, is the number 4). We set a variable called lastFriday to today's date and work backward until we have reached a date with the desired weekday value of 4.

Once we have the date we desire, formatting the date in any way we like is easily achieved with the "string formatting" method strftime of the datetime.date class.

An alternative, slightly more terse solution uses the built-in constant datetime.date.resolution instead of explicitly building the datetime.timedelta instance to represent one day's duration:

import datetime, calendar lastFriday = datetime.date.today( ) while lastFriday.weekday( ) != calendar.FRIDAY:     lastFriday -= datetime.date.resolution print lastFriday.strftime('%d-%b-%Y')

The datetime.date.resolution class attribute has exactly the same value as the oneday variable in the recipe's Solutionthe time interval of one day. However, resolution can trip you up. The value of the class attribute resolution varies among various classes of the datetime modulefor the date class it's timedelta(days=1), but for the time and datetime classes , it's timedelta(microseconds=1). You could mix-and-match (e.g., add datetime.date.resolution to a datetime.datetime instance), but it's easy to get confused doing so. The version in this recipe's Solution, using the explicitly named and defined oneday variable, is just as general, more explicit, and less confusing. Thus, all in all, that version is more Pythonic (which is why it's presented as the "official" one!).

A more important enhancement is that we don't really need to loop, decrementing a date by one at each step through the loop: we can, in fact, get to the desired target in one fell swoop, computing the number of days to subtract thanks to the wonders of modular arithmetic:

import datetime, calendar today = datetime.date.today( ) targetDay = calendar.FRIDAY thisDay = today.weekday( ) deltaToTarget = (thisDay - targetDay) % 7 lastFriday = today - datetime.timedelta(days=deltaToTarget) print lastFriday.strftime('%d-%b-%Y')

If you don't follow why this works, you may want to brush up on modular arithmetic, for example at http://www.cut-the-knot.org/blue/Modulo.shtml.

Use the approach you find clearest, without worrying about performance. Remember Hoare's dictum (often misattributed to Knuth, who was in fact quoting Hoare): "premature optimization is the root of all evil in programming." Let's see why thinking of optimization would be premature here.

Net of the common parts (computing today's date, and formatting and emitting the result) on a four-year-old PC, with Linux and Python 2.4, the slowest approach (the one chosen for presentation as the "Solution" because it's probably the clearest and most obvious one) takes 18.4 microseconds; the fastest approach (the one avoiding the loop, with some further tweaks to really get pedal to the metal ) takes 10.1 microseconds.

You're not going to compute last Friday's date often enough, in your life, to be able to tell the difference at 8 microseconds a pop (much less if you use recent hardware rather than a box that's four years old). If you consider the time needed to compute today's date and to format the result, you need to add 37 microseconds to each timing, even net of the I/O time for the print statement; so, the range of performance is roughly between 55 microseconds for the slowest and clearest form, and 47 microseconds for the fastest and tersest oneclearly not worth worrying about.

See Also

datetime module and strftime documentation in the Library Reference (currently at http://www.python.org/doc/lib/module-datetime.html and http://www.python.org/doc/current/lib/node208.html).



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net