2013-08-23 2 views
1

Я пытаюсь создать канал ICal, используя Data: ICal, но некоторые события печатаются без какого-либо времени. Я читал, что время не требуется, если оно 000000, но Календарь Google не обрабатывает эти события без надлежащего времени.Perl Data :: ICal печатает время события как T000000Z вместо того, чтобы опускать его

Вот пример сценария и вывода. Мне нужно, чтобы выход находился в часовом поясе 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

Я прочитал, что время не требуется, если это 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 после него.

Что приводит нас к дате :: 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; 
+1

Спасибо за подробное объяснение. Я закончил делать замену после конвертации в UTC, и это работает нормально. – Vlad

 Смежные вопросы

  • Нет связанных вопросов^_^