Kurt McKee ([info]kurtmckee) wrote,
@ 2009-06-21 19:58:00
Previous Entry  Add to memories!  Tell a Friend  Next Entry
Entry tags:listparser

Normalizing years

I've been implementing the RFC 822 date and time specification in listparser in order to support the dateCreated and dateModified tags, and while doing so I've found a fun problem to mull over.

RFC 822, in classic shortsighted fashion, calls for years to be represented using only two digits. OPML calls for years to be either two digits or four digits. Thus, the following two dates are equivalent:

Sun, 21 Jun 09 19:22:00 CDT
Sun, 21 Jun 2009 19:22:00 CDT

The problem is ensuring that the year is always four digits long by the end of the program. One simple way to do this is to use the following, assuming arbitrarily that everything in the 90's is the 1990's, and everything else is in the 21st century:

if year < 100:
    if year >= 90:
        year += 1900
    else:
        year += 2000

After writing that code, I was so disgusted that I rewrote it as a single line with no if statements at all:

year += (year < 100) * (19 + (year < 90)) * 100

I'm abusing the fact that False and True evaluate to 0 and 1, respectively. Unfortunately, this is magic and unmaintainable code. I lamented that Python didn't have a ternary operator, then realized that I had never actually checked. Sure enough:

if year < 100:
    year += 1900 if year >= 90 else 2000

Much more maintainable, but ternary operators were only introduced in Python 2.5, which not everyone might have. Happily, Wikipedia's entry on ternary operators introduced me to using booleans as list indices (which hadn't occurred to me, despite knowing that they evaluated to 0 and 1 in arithmetic). Here's the final, reasonable, readable code:

if year < 100:
    year += (1900, 2000)[year < 90]

I expect to have another listparser release out next week.

UPDATE

Heh, I guess I could remove the if statement again by extending the above concept:

year += (0, 1900, 2000)[(year < 90) + (year < 100)]



(4 comments) - (Post a new comment)


(Anonymous)
2009-06-22 03:58 am UTC (link)
Yeah, but throw in a way to include dates past the year 10000. That'd kick ass.

(Reply to this) (Thread)


[info]kurtmckee
2009-06-22 05:28 am UTC (link)
It'll be easy! I'll simply assume that the years 1990-9999 are from this decamillenium, but 0000-1989 are referencing the next.

(Reply to this) (Parent)


[info]Herohtar [myopenid.com]
2009-06-23 07:46 pm UTC (link)
Clever... I probably would have used this:

year += (year < 90) and 2000 or (year < 100) and 1900 or 0

(Reply to this) (Thread)


[info]kurtmckee
2009-06-23 08:26 pm UTC (link)
Nice. I'm particularly impressed that it doesn't use parentheses to do explicitly what the default order of operations already does. I have a habit of always using parentheses, even if the order or operations would accomplish the same logic.

(Reply to this) (Parent)


(4 comments) - (Post a new comment)

Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…