Perl Data :: ICal打印事件时间为T000000Z而不是省略它

时间:2013-08-23 21:59:43

标签: perl date perl-module utc icalendar

我正在尝试使用Data:ICal生成ICal Feed,但有些事件是在没有时间的情况下打印的。我已经读过,如果它是000000,则不需要时间,但Google日历在没有正确时间的情况下无法处理这些事件。

这是一个示例脚本和输出。我需要输出到UTC时区。

#!/usr/bin/perl -w
use strict;
use Date::ICal;
use Data::ICal;
use Data::ICal::Entry::Event;
use DateTime;
use Data::Dumper;

sub get_utc_offset($) {
    my ($orig_tz_str) = @_;

    # Using a set winter date to avoid problems with daylight savings time
    my $utc_compare_datetime = DateTime->new(
        year      => 2012,
        month     => 1,
        day       => 1,
        hour      => 1,
        minute    => 1,
        time_zone => 'UTC'
    );

    my $tz             = DateTime::TimeZone->new(name => $orig_tz_str);
    my $utc_offset     = $tz->offset_for_datetime($utc_compare_datetime);
    my $utc_offset_str = DateTime::TimeZone->offset_as_string($utc_offset);

    return $utc_offset_str;
}

sub add_ical_event($$$$$$) {
    my ($calendar, $start, $end, $summary, $description, $timezone) = @_;
    my $offset   = get_utc_offset($timezone);
    $description = 'none' if (!$description);

    my $event = Data::ICal::Entry::Event->new();
    $event->add_properties(
        summary     => $summary,
        description => $description,
        dtstart     => Date::ICal->new( ical  => $start, offset => $offset )->ical,
        dtend       => Date::ICal->new( ical  => $end,   offset => $offset )->ical,
        dtstamp     => Date::ICal->new( epoch => time                      )->ical
    );
    $calendar->add_entry($event);
}


# Tests
# ----------------------------------------------------------------------------

my $timezone = 'America/New_York';

my $calendar = Data::ICal->new();
$calendar->add_properties(
    method         => "PUBLISH",
    prodid         => "-//Test Cal//NONSGML Calendar//EN",
    'X-WR-CALNAME' => 'Test Cal'
);

my (%events) = (
    1 => {
        summary     => 'Test Shift Tool - Testing Shift',
        description => '',
        start       => '20130828T160000',
        end         => '20130828T190000',
        timezone    => $timezone
    },
    2 => {
        summary     => 'New Member Meeting',
        description => '',
        start       => '20130722T190000',
        end         => '20130722T210000',
        timezone    => $timezone
    },
    3 => {
        summary     => 'public',
        description => '',
        start       => '20130630T130000',
        end         => '20130630T140000',
        timezone    => $timezone
    }
);
foreach my $key (sort keys %events) {
    my $e = $events{$key};
    add_ical_event(
        $calendar,
        $e->{start},
        $e->{end},
        $e->{summary},
        $e->{description},
        $e->{timezone}
    );
}
print $calendar->as_string;

请注意,某些事件的开始日期或结束日期没有时间。当我手动添加T000000Z时,这些事件会正确导入Google日历。关于如何强迫所有活动有时间的任何建议?

BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
PRODID:-//Digital Cheetah//NONSGML Calendar//EN
X-WR-CALNAME:Digital Cheetah
BEGIN:VEVENT
DESCRIPTION:none
DTEND:20130829Z
DTSTAMP:20130823T214317Z
DTSTART:20130828T210000Z
SUMMARY:Test Shift Tool - Testing Shift
END:VEVENT
BEGIN:VEVENT
DESCRIPTION:none
DTEND:20130723T020000Z
DTSTAMP:20130823T214317Z
DTSTART:20130723Z
SUMMARY:New Member Meeting
END:VEVENT
BEGIN:VEVENT
DESCRIPTION:none
DTEND:20130630T190000Z
DTSTAMP:20130823T214317Z
DTSTART:20130630T180000Z
SUMMARY:public
END:VEVENT
END:VCALENDAR

1 个答案:

答案 0 :(得分:1)

  

我已经读过,如果它是000000

,则不需要时间

That's not what the RFC says。让我们参考以下部分:

  • 4。3。4日期
  • 4。3。5日期时间
  • 4。8。7。2日期/时间

我将引用相关的格式规范,在这里:

date               = date-value

date-value         = date-fullyear date-month date-mday
date-fullyear      = 4DIGIT

date-time  = date "T" time ;As specified in the date and time
                             ;value definitions

dtstamp    = "DTSTAMP" stmparam ":" date-time CRLF

当您的输出包含DTSTAMP时,ICal规范要求date-time跟随它。

它将我们带到Date :: ICal及其ical方法。它会返回iCal date还是date-time?事实证明,它会通过检查您的时间戳是否具有000000的时间来尝试猜测您想要的格式。请参阅line 286 of ICal.pm

可能是我们期望Data :: ICal :: Entry来处理这种情况。我可能在这方面缺少验证码,但目前我没有看到任何明显相关的东西。看起来它接受属性值而不检查它们。

根据您的观点,这听起来像是一个错误或库的限制。

那么......你应该怎么解决这个问题?理想情况下,这些库中的一个应该检查并处理这种情况。与此同时,你需要重新站起来:

快速而肮脏的修复:如果您的时间为零,则将其提高一秒钟; ical现在会返回一个有效但稍微不准确的date-time字符串。

好一点:检查ical的返回值;如果是date,请将其重新格式化为date-time

在使用之前测试一下,但也许是这样的:

dtstart => $ical =~ s/(\d{8})Z/$1T000000Z/r;