Perl DateTime objects, time zones, and ISO8601

Here’s what I want to do. DateTime objects conveniently stringify to their ISO8601 date representation. But last week the clocks changed, and all my code broke, because this representation doesn’t include the time zone. I want a DateTime object that will stringify to an ISO8601 date including a timezone. Shouldn’t be too hard.

Let’s look at the perldoc for DateTime::Format::ISO8601. There’s an awful lot of things that can be called an ISO8601 date string. 20060101T120000+0100 is a valid date. 2006-01-01T12:00:00+01:00 is also a valid date string. Personally, I prefer the latter. And fortunately, the W3C have looked at this mess and decided ‘It’s too complicated‘. And they agree with me. So this is the string that I want to produce.

DateTime.pm provides a formatter method – you can define a formatter class that will stringify the object. Horay. But using DateTime::Formatter::ISO8601 doesn’t produce a string with a time zone. My next plan is to use DateTime::Format::Strptime and provide a strptime spec that will produce the right string. To the DateTime / strftime docs! Apparently, %FT%T produces a nice 2006-01-01T12:00:00, so all we need is the time zone. And again, here is where we fail. There’s %z, but that produces +0100, and I need +01:00.

At this point, I write a hack and get back to work. DateTime lets you use the magic format specifier %{ method_name } to call a method of the DateTime object. So I push a method into the DateTime namespace that produces the string that I want.

sub DateTime::iso8601_with_tz {
  my $self = shift;
  my $val = $self->strftime('%FT%T%z');
  $val =~ s/(dd)$/:$1/;
  return $val;
}

Then I can create a formatter that will format DateTime objects the way I want them.

use DateTime::Format::Strptime;
my $formatter = DateTime::Format::Strptime->new( pattern => "%{iso8601_with_tz}" )

Finally, I can use this as my formatter.

$my_datetime->formatter( $formatter );

Nasty.

Bot::BasicBot::Pluggable 0.50

finally, I have a Bot::BasicBot::Pluggable release out. muttley’s been bugging me for weeks, and the last release was in June 2003, which is ridiculous. When you just use things straight from the svn repository, you forget how long it is since you’ve done a release.

There’s a Bot::BasicBot 0.60 release to go along with it, with better character set support, no massive improvements, though. I should push that guy to 1.0 soon…

photo gallery

All I want, and I don’t feel that this is a lot, is to be able to put photos on my web page from iPhoto. Because writing iPhoto plugins is a pain, this requires me to use either Flickr, which I don’t want to (because I’d like to control my own photos, please, and not pay money for it), or php gallery, which has it’s own issues for me, mostly that it’s written in php.

As a perl (most of the time) programmer, I resent the fact that my web page is increasingly powered by php, but alas that’s where all these little toys come from nowadays. I’ve dabbled in php myself a little now, and it seems like a bearable language, although not one I’d actually want to write serious code in. Of course, with my colo going through.. pain recently, it’s tempting to restrict myself to a very simple subset of things, specifically, a subset of the stuff that the main box admin uses, because I know that it works and I don’t have to think about it. No more compiling weird perl/C modules on solaris as root with bizarre things tacked onto the end of my library path for me. The other colo has debian on it, which I like, but only 64 megs of memory, which I don’t. Hardware (even virtual hardware) sucks.

Of course, having got a gallery, I want to do things like have ‘5 most recent’ pictures on the front page of the site, and this is where things fall down a little. Noone else seems to want to do this stuff – I may end up subscribing to my own RSS feed, syndicating from one bit of my site to another, which seems disgustingly wasteful.

unit tests

Tests are a blessing and a curse. They are the developer’s friend – I can barely write code nowadays without a test suite. How else will I know when I’ve broken something? I’m very lazy – I can’t be bothered to manually run through every feature, or even to start up the web server (or whatever) in most cases. Edit, save, run tests, edit again, is my preferred cycle, and for this, the tests must be as comprehensive as possible – not only testing the features, but testing the things that shouldn’t work, and testing every nasty, hard-to-track-down bug you’ve ever found – there’s nothing worse than spending hours tracking down the same bug that you fixed last month.

But for deployment, tests are just annoying. Take CPAN modules, for instance. Most of the time, yay, tests pass, install the module. But as with all things, all the interesting things happen when things break, and the tests don’t pass. In my experience, if there are any failures at all, either all the tests fail, because there’s a dependancy that failed to build and you can’t even ‘use’ the module, or one or two out of 45,000 tests failed, because there’s a tiiiny little broken case on whatever bizarre architecture I’m using this week, and I’m just going to force install it anyway. This would seem to be served better by a much simpler ‘does the thing superficially work?’ test suite used for deployment, separate from the development test suite.

Writing recursive closures

I discovered the other day that you can do quite horrifying things with perl. A closure in perl is a nice concept – it’s a block that can reference things in the scope that it’s declared in, but that can be passed around and used in quite different scopes. For instance, suppose I wanted a function that, say, converted a string to utf8 bytes (yes, I’m obsessed with utf8). I can do this like this:

my $closure;
$closure = sub {
  my $val = shift;
  return Encode::encode("utf8", $val);
};

And call it later as:

print $closure->("héllo");

This is dead nifty. But because a closure can reference things in it’s scope, and $closure is in it’s scope, it can call itself, or at least, it can call the function pointed at by $closure. So we can make this function recursive:

$closure = sub {
  my $val = shift;
  if (ref $val eq "ARRAY") {
    return [ map { $closure->($_) } @$val ];
  } elsif (ref $val eq "HASH") {
    return { map { $_ => $closure->($_) } keys(%$val) };
  } else {
    return Encode::encode("utf8", $val);
  }
};

Until the assignment is complete, the inside of the closure won’t work, because $closure is undefined. But by the time we call it later..

return $closure->( [ "héllo", { foo =>"bår" } ] );

..everything works.

Crazy, I tell you.

UTF8 Openguides

I foolishly offered to make OpenGuides UTF-8 safe. Because I don’t do that enough at work, or something. Anyway, it’s going quite well – because I did all the grunt work in CGI::Wiki a while ago, it’s just a matter of finding all the inputs and outputs and making sure they’re encoded properly. So far, the page contents and names are utf-8 safe, along with the cookie preferences, so your username is good. The search stuff looks scary, and there are various broken plugins, etc, etc, so there’s still stuff to do. I should also do the hooks properly – CGI::Wiki should offer nice functions for this stuff.

London Perl Workshop talk

I gave a talk today at the London Perl Workshop, brilliantly organised by a shadowy cabal of mysterious figures. Every talk I saw was great, to the point that the inevitable clashes with other talks that I wanted to see were really annoying, but fortunately everything was filmed, so presumably there’ll be video of the talks I missed available at some point. Likewise, all the slides will be around at some point, but until then, my slides are here. Powerpoint, I’m afraid, it’s what the work laptop has, and 1.5 megs, because it’s full of pictures…