ical2org.pl 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #!/usr/bin/env perl
  2. use warnings;
  3. use strict;
  4. use Data::ICal;
  5. use Data::Dumper;
  6. use DateTime::Format::ICal;
  7. use Getopt::Long;
  8. my $category = 'ical';
  9. GetOptions(
  10. 'category|c=s' => \$category
  11. );
  12. my $cal = Data::ICal->new(data => join '', <STDIN>);
  13. #print Dumper $cal;
  14. my %gprops = %{ $cal->properties };
  15. print "#+TITLE: ical entries\n";
  16. print "#+AUTHOR: ".$gprops{'x-wr-calname'}[0]->decoded_value."\n";
  17. print "#+EMAIL: \n";
  18. print "#+DESCRIPTION: Converted using ical2org.pl\n";
  19. print "#+CATEGORY: $category\n";
  20. print "#+STARTUP: overview\n";
  21. print "\n";
  22. print "* COMMENT original iCal properties\n";
  23. #print Dumper \%gprops;
  24. print "Timezone: ", $gprops{'x-wr-timezone'}[0]->value, "\n";
  25. foreach my $prop (values %gprops) {
  26. foreach my $p (@{ $prop }) {
  27. print $p->key, ':', $p->value, "\n";
  28. }
  29. }
  30. foreach my $entry (@{ $cal->entries }) {
  31. next if not $entry->isa('Data::ICal::Entry::Event');
  32. #print 'Entry: ', Dumper $entry;
  33. my %props = %{ $entry->properties };
  34. my $dtstart = DateTime::Format::ICal->parse_datetime($props{dtstart}[0]->value);
  35. my $dtend = DateTime::Format::ICal->parse_datetime($props{dtend}[0]->value);
  36. my $duration = $dtend->subtract_datetime($dtstart);
  37. if (defined $props{rrule}) {
  38. #print " REPEATABLE\n";
  39. # Bad: There may be multiple rrules but I'm ignoring them
  40. my $set = DateTime::Format::ICal->parse_recurrence(
  41. recurrence => $props{rrule}[0]->value,
  42. dtstart => $dtstart,
  43. dtend => DateTime->now->add(weeks => 1),
  44. );
  45. my $itr = $set->iterator;
  46. while (my $dt = $itr->next) {
  47. $dt->set_time_zone(
  48. $props{dtstart}[0]->parameters->{'TZID'} ||
  49. $gprops{'x-wr-timezone'}[0]->value
  50. );
  51. print "* ".$props{summary}[0]->decoded_value."\n";
  52. my $end = $dt->clone->add_duration($duration);
  53. print ' ', org_date_range($dt, $end), "\n";
  54. #print $dt, "\n";
  55. print " :PROPERTIES:\n";
  56. printf " :ID: %s\n", $props{uid}[0]->value;
  57. if (defined $props{location}) {
  58. printf " :LOCATION: %s\n", $props{location}[0]->value;
  59. }
  60. if (defined $props{status}) {
  61. printf " :STATUS: %s\n", $props{status}[0]->value;
  62. }
  63. print " :END:\n";
  64. if ($props{description}) {
  65. print "\n", $props{description}[0]->decoded_value, "\n";
  66. }
  67. }
  68. }
  69. else {
  70. print "* ".$props{summary}[0]->decoded_value."\n";
  71. my $tz = $gprops{'x-wr-timezone'}[0]->value;
  72. $dtstart->set_time_zone($props{dtstart}[0]->parameters->{'TZID'} || $tz);
  73. $dtend->set_time_zone($props{dtend}[0]->parameters->{'TZID'} || $tz);
  74. print ' ', org_date_range($dtstart, $dtend), "\n";
  75. print " :PROPERTIES:\n";
  76. printf " :ID: %s\n", $props{uid}[0]->value;
  77. if (defined $props{location}) {
  78. printf " :LOCATION: %s\n", $props{location}[0]->value;
  79. }
  80. if (defined $props{status}) {
  81. printf " :STATUS: %s\n", $props{status}[0]->value;
  82. }
  83. print " :END:\n";
  84. if ($props{description}) {
  85. print "\n", $props{description}[0]->decoded_value, "\n";
  86. }
  87. }
  88. # print Dumper \%props;
  89. }
  90. sub org_date_range {
  91. my $start = shift;
  92. my $end = shift;
  93. my $str = sprintf('<%04d-%02d-%02d %s %02d:%02d>',
  94. $start->year,
  95. $start->month,
  96. $start->day,
  97. $start->day_abbr,
  98. $start->hour,
  99. $start->minute
  100. );
  101. $str .= '--';
  102. $str .= sprintf('<%04d-%02d-%02d %s %02d:%02d>',
  103. $end->year,
  104. $end->month,
  105. $end->day,
  106. $end->day_abbr,
  107. $end->hour,
  108. $end->minute
  109. );
  110. return $str;
  111. }