Your Mother has asked for the wisdom of the Perl Monks concerning the following question:

This terrific stuff— Types::DateTime, tobyink—is going into something I’m working on. Out of the box it is parsing perfectly–

use 5.12.0; package CowTime { use Moo; use Types::DateTime -all; has timestamp => is => "ro", isa => DateTimeUTC->plus_coercions( Format['ISO8601'] ), coerce => 1; 1; }; my $original = "2019-12-07T00:07:40.587596283-05:00"; my $cowtime = CowTime->new( timestamp => $original ); say $original; say $cowtime->timestamp->time_zone; say $cowtime->timestamp->nanosecond; say $cowtime->timestamp; __END__ 2019-12-07T00:07:40.587596283-05:00 2019-12-07T05:07:40 DateTime::TimeZone::UTC=HASH(0x7f9e85ba3cd0) 587596283

It’s pulling apart the input perfectly but the output is the standard format and I’m looking for the “extended” format of the input such that the stringification will roundtrip to the form with the offset and the nanoseconds. I was set to code dive and look for the formatting hooks but I thought this was a really interesting package and wanted to put it up here. Also, I am lazy.

  • Comment on Types::DateTime, DateTimeUTC->plus_coercions( Format['ISO8601'] ), output format override question
  • Download Code

Replies are listed 'Best First'.
Re: Types::DateTime, DateTimeUTC->plus_coercions( Format['ISO8601'] ), output format override question
by tobyink (Canon) on Dec 24, 2019 at 22:03 UTC

    As per ikegami's answer (Re: Types::DateTime, DateTimeUTC->plus_coercions( Format['ISO8601'] ), output format override question), you want to set a formatter on the DateTime object.

    $cowtime->timestamp->set_formatter($formatter);

    But you probably want your CowTime class to be doing that automatically. You can do that with triggers:

    use 5.12.0; package CowTime { use Moo; use Types::DateTime -all; has timestamp => is => "ro", isa => DateTimeUTC->plus_coercions( Format['ISO8601'] ), coerce => 1, trigger => sub { my ($self, $value) = @_; state $formatter = DateTime::Format::MyFormatter->new; $value->set_formatter($formatter); }; 1; };

    The trigger is a coderef which gets called any time you set the value of an attribute. (Though it's not set if the attribute is set by a default/builder.)

      Though it's not set if the attribute is set by a default/builder.

      That makes this a particularly bad solution, then.

        Why? OP isn't using a default or builder. (Not in the example anyway.)

Re: Types::DateTime, DateTimeUTC->plus_coercions( Format['ISO8601'] ), output format override question
by ikegami (Patriarch) on Dec 24, 2019 at 14:39 UTC

    $cowtime->timestamp is a DateTime object, so you could use the following:

    $cowtime->timestamp->strftime("%Y-%m-%dT%H:%M:%S.%9N%z") =~ s/(?=..\z) +/:/sr

    I'm not aware of any DateTime::Format::* class that would produce the format you want. If there was you could set it as the default format (used for stringification) using the following:

    use DateTime::Format::Foo qw( ); my $format = DateTime::Format::Foo->new(...); $cowtime->timestamp->set_formatter($format);