|
Packit |
9002b2 |
# we need to comment this out or PAUSE might index it
|
|
Packit |
9002b2 |
# pack age DateTime::Format::ICal;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
use strict;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
use DateTime;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
# Builder relevant stuff starts here.
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
use DateTime::Format::Builder parsers => {
|
|
Packit |
9002b2 |
parse_datetime => [
|
|
Packit |
9002b2 |
[ preprocess => \&_parse_tz ],
|
|
Packit |
9002b2 |
{
|
|
Packit |
9002b2 |
length => 15,
|
|
Packit |
9002b2 |
params => [qw( year month day hour minute second )],
|
|
Packit |
9002b2 |
regex => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)$/,
|
|
Packit |
9002b2 |
},
|
|
Packit |
9002b2 |
{
|
|
Packit |
9002b2 |
length => 13,
|
|
Packit |
9002b2 |
params => [qw( year month day hour minute )],
|
|
Packit |
9002b2 |
regex => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)$/,
|
|
Packit |
9002b2 |
},
|
|
Packit |
9002b2 |
{
|
|
Packit |
9002b2 |
length => 11,
|
|
Packit |
9002b2 |
params => [qw( year month day hour )],
|
|
Packit |
9002b2 |
regex => qr/^(\d\d\d\d)(\d\d)(\d\d)T(\d\d)$/,
|
|
Packit |
9002b2 |
},
|
|
Packit |
9002b2 |
{
|
|
Packit |
9002b2 |
length => 8,
|
|
Packit |
9002b2 |
params => [qw( year month day )],
|
|
Packit |
9002b2 |
regex => qr/^(\d\d\d\d)(\d\d)(\d\d)$/,
|
|
Packit |
9002b2 |
},
|
|
Packit |
9002b2 |
],
|
|
Packit |
9002b2 |
};
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
sub _parse_tz {
|
|
Packit |
9002b2 |
my %args = @_;
|
|
Packit |
9002b2 |
my ( $date, $p ) = @args{qw( input parsed )};
|
|
Packit |
9002b2 |
if ( $date =~ s/^TZID=([^:]+):// ) {
|
|
Packit |
9002b2 |
$p->{time_zone} = $1;
|
|
Packit |
9002b2 |
}
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
# Z at end means UTC
|
|
Packit |
9002b2 |
elsif ( $date =~ s/Z$// ) {
|
|
Packit |
9002b2 |
$p->{time_zone} = 'UTC';
|
|
Packit |
9002b2 |
}
|
|
Packit |
9002b2 |
else {
|
|
Packit |
9002b2 |
$p->{time_zone} = 'floating';
|
|
Packit |
9002b2 |
}
|
|
Packit |
9002b2 |
return $date;
|
|
Packit |
9002b2 |
}
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
# Builder relevant stuff ends here.
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
sub parse_duration {
|
|
Packit |
9002b2 |
my ( $self, $dur ) = @_;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
my @units = qw( weeks days hours minutes seconds );
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
$dur =~ m{ ([\+\-])? # Sign
|
|
Packit |
9002b2 |
P # 'P' for period? This is our magic character)
|
|
Packit |
9002b2 |
(?:
|
|
Packit |
9002b2 |
(?:(\d+)W)? # Weeks
|
|
Packit |
9002b2 |
(?:(\d+)D)? # Days
|
|
Packit |
9002b2 |
)?
|
|
Packit |
9002b2 |
(?: T # Time prefix
|
|
Packit |
9002b2 |
(?:(\d+)H)? # Hours
|
|
Packit |
9002b2 |
(?:(\d+)M)? # Minutes
|
|
Packit |
9002b2 |
(?:(\d+)S)? # Seconds
|
|
Packit |
9002b2 |
)?
|
|
Packit |
9002b2 |
}x;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
my $sign = $1;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
my %units;
|
|
Packit |
9002b2 |
$units{weeks} = $2 if defined $2;
|
|
Packit |
9002b2 |
$units{days} = $3 if defined $3;
|
|
Packit |
9002b2 |
$units{hours} = $4 if defined $4;
|
|
Packit |
9002b2 |
$units{minutes} = $5 if defined $5;
|
|
Packit |
9002b2 |
$units{seconds} = $6 if defined $6;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
die "Invalid ICal duration string ($dur)\n"
|
|
Packit |
9002b2 |
unless %units;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
if ( $sign eq '-' ) {
|
|
Packit |
9002b2 |
$_ *= -1 foreach values %units;
|
|
Packit |
9002b2 |
}
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
return DateTime::Duration->new(%units);
|
|
Packit |
9002b2 |
}
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
sub format_datetime {
|
|
Packit |
9002b2 |
my ( $self, $dt ) = @_;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
my $tz = $dt->time_zone;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
unless ( $tz->is_floating || $tz->is_utc || $tz->name ) {
|
|
Packit |
9002b2 |
$dt = $dt->clone->set_time_zone('UTC');
|
|
Packit |
9002b2 |
$tz = $dt->time_zone;
|
|
Packit |
9002b2 |
}
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
my $base = (
|
|
Packit |
9002b2 |
$dt->hour || $dt->min || $dt->sec
|
|
Packit |
9002b2 |
? sprintf(
|
|
Packit |
9002b2 |
'%04d%02d%02dT%02d%02d%02d',
|
|
Packit |
9002b2 |
$dt->year, $dt->month, $dt->day,
|
|
Packit |
9002b2 |
$dt->hour, $dt->minute, $dt->second
|
|
Packit |
9002b2 |
)
|
|
Packit |
9002b2 |
: sprintf( '%04d%02d%02d', $dt->year, $dt->month, $dt->day )
|
|
Packit |
9002b2 |
);
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
return $base if $tz->is_floating;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
return $base . 'Z' if $tz->is_utc;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
return 'TZID=' . $tz->name . ':' . $base;
|
|
Packit |
9002b2 |
}
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
sub format_duration {
|
|
Packit |
9002b2 |
my ( $self, $duration ) = @_;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
die "Cannot represent years or months in an iCal duration\n"
|
|
Packit |
9002b2 |
if $duration->delta_months;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
# simple string for 0-length durations
|
|
Packit |
9002b2 |
return '+PT0S'
|
|
Packit |
9002b2 |
unless $duration->delta_days || $duration->delta_seconds;
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
my $ical = $duration->is_positive ? '+' : '-';
|
|
Packit |
9002b2 |
$ical .= 'P';
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
if ( $duration->delta_days ) {
|
|
Packit |
9002b2 |
$ical .= $duration->weeks . 'W' if $duration->weeks;
|
|
Packit |
9002b2 |
$ical .= $duration->days . 'D' if $duration->days;
|
|
Packit |
9002b2 |
}
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
if ( $duration->delta_seconds ) {
|
|
Packit |
9002b2 |
$ical .= 'T';
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
$ical .= $duration->hours . 'H' if $duration->hours;
|
|
Packit |
9002b2 |
$ical .= $duration->minutes . 'M' if $duration->minutes;
|
|
Packit |
9002b2 |
$ical .= $duration->seconds . 'S' if $duration->seconds;
|
|
Packit |
9002b2 |
}
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
return $ical;
|
|
Packit |
9002b2 |
}
|
|
Packit |
9002b2 |
|
|
Packit |
9002b2 |
1;
|