Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Ovid (2709)

Ovid
  (email not shown publicly)
http://publius-ovidius.livejournal.com/
AOL IM: ovidperl (Add Buddy, Send Message)

Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.

Journal of Ovid (2709)

Monday June 16, 2008
03:50 AM

DateTime::Duration refinement

[ #36696 ]

Recently we found we needed to support DateTime::Duration objects a bit more "naturally". Specifically, we needed something like this:

my $duration = Our::DateTime::Duration->new( seconds => 23.127 );
# later
print $duration->in_seconds;   # 23.127

Note that this doesn't work in DateTime::Duration. We've already subclassed it for our own purposes, so it was natural (*cough*) to add this feature, but even though the interface is simple, the guts are horrifying and confusing. I'm hoping one of you can tell me the error of my ways :)

I made this work by hijacking "nanoseconds", something that the duration objects already support but which we do not use (the following code is simplified to show the relevant logic).

sub new {

    my ( $self, %args ) = @_;

    if ( exists $args{seconds} && $args{seconds} =~ /\./ ) {
        my $seconds = $args{seconds};
        @args{qw[seconds nanoseconds]} = split /\./ => $seconds;
        $args{nanoseconds} ||= 0;

        my $length = length $args{nanoseconds};
        if ( $length > 9 ) {
            X::TVA::Field::Format::Duration::Seconds::Invalid->throw(
                seconds => $seconds,
            );
        }

        # XXX need to zero fill to fill out the 'billions'
        $args{nanoseconds} .= '0' x ( 9 - $length );
    }
    return $self->SUPER::new(%args);
}

You'll note the "zero padding" to get nanoseconds correct. We have to do something very similar to make the in_seconds method work.

sub in_seconds {
    my $d = shift;

    my $seconds = (($d->hours * 60) + $d->minutes) * 60 + $d->seconds;
    if ( my $nanoseconds = $d->nanoseconds ) {
        $nanoseconds =  ( '0' x ( 9 - length($nanoseconds) ) ) . $nanoseconds;
        $seconds .= ".$nanoseconds";
        $seconds += 0; # handy way to trim those trailing zeros
    }
    return $seconds;
}

This is horrifying to me. I'm using string manipulation to do math :( Do you have anything better?

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • I can't tell if I'm being really dense, but what's the difference between your desired output, and this...?

    $d = DateTime::Duration->new( seconds => 23.127 );
    print $d->delta_seconds; # 23.127

    In which case, wouldn't this provide the 'natural' method name...

    *DateTime::Duration::in_seconds = \&DateTime::Duration::delta_seconds;