RubyでiCalendarを利用する
RubyでiCalendar形式を使いたくて、ちょっと調べたらやっぱりありました。
Ruby用iCalendarライブラリ♪->http://icalendar.rubyforge.org/
インストールしたiCalendarライブラリのバージョンは0.98です。
gemで一発インストール
$ gem install icalendar
サンプル(READMEから)
require 'rubygems' require 'icalendar' # Create a calendar with an event (standard method) cal = Icalendar::Calendar.new cal.event do dtstart Date.new(2005, 04, 29) dtend Date.new(2005, 04, 28) summary "Meeting with the man." description "Have a long lunch meeting and decide nothing..." klass "PRIVATE" end
ん〜便利♪
ただ、ちょっといじってたらどうもtimezoneがバグってるみたいです。
timezoneを使ってる状態で、to_icalメソッドを利用すると、エラーを出します。
これも、ちょっと調べたら、パッチがありました。
timezone用パッチ
---[patch begin]--- diff -c /home/trac/ruby/gem/gems/icalendar-0.98/lib/icalendar/component/timezone.rb.org /home/trac/ruby/gem/gems/icalendar-0.98/lib/icalendar/component/timezone.rb *** /home/trac/ruby/gem/gems/icalendar-0.98/lib/icalendar/component/timezone.rb.org Wed May 2 13:45:15 2007 --- /home/trac/ruby/gem/gems/icalendar-0.98/lib/icalendar/component/timezone.rb Mon May 7 08:40:32 2007 *************** *** 49,58 **** # Also need a custom to_ical because typically it iterates over an array # of components. def to_ical ! print_component do |s| @components.each_value do |comp| s << comp.to_ical end end end --- 49,60 ---- # Also need a custom to_ical because typically it iterates over an array # of components. def to_ical ! print_component do ! s = "" @components.each_value do |comp| s << comp.to_ical end + s end end ---[patch end]---
これで、一応to_icalメソッドが通るようにはなるんですけど、
cal = Icaledar::Calendar.new cal.timezone do tzid 'Asia/Tokyo' standard do tzoffsetfrom '+0900' tzoffsetto '+0900' dtstart '19700101T000000' tzname 'JST' end end
という感じで、standardを使っても、一切反応してくれません。なんで・・・
ソース見てもぶっちゃけよくわからないんで、
とりあえず、図書館で借りた本の返却日をGoogle Calendarに反映する その3 - Action!!を参考にtimezone部分を作成。
cal = Icalendar::Calendar.new # STANDARD コンポーネントを生成 standard_component = Icalendar::Component.new('STANDARD') standard_component.custom_property('dtstart', '19700101T000000') standard_component.custom_property('tzoffsetfrom', '+0900') standard_component.custom_property('tzoffsetto', '+0900') standard_component.custom_property('tzname', 'JST') # VTIMEZONE コンポーネントを生成 vtimezone_component = Icalendar::Component.new('VTIMEZONE') vtimezone_component.custom_property('tzid', 'Asia/Tokyo') vtimezone_component.add(standard_component) cal.add(vtimezone_component)
ちなみに、custom_propertyの第一引数は、自動的に大文字になります。
んで、これを使って、iCalendarのサンプルは以下のようになります。
iCalendarのサンプル
require 'rubygems' require 'icalendar' require 'kconv' cal = Icalendar::Calendar.new # イベントを作成 cal.event do dtstart DateTime.new(2007, 07, 02, 10) dtend DateTime.new(2005, 07, 02, 20) summary "Meeting with the man." description "Have a long lunch meeting and decide nothing..." klass "PRIVATE" end # STANDARD コンポーネントを生成 standard_component = Icalendar::Component.new('STANDARD') standard_component.custom_property('dtstart', '19700101T000000') standard_component.custom_property('tzoffsetfrom', '+0900') standard_component.custom_property('tzoffsetto', '+0900') standard_component.custom_property('tzname', 'JST') # VTIMEZONE コンポーネントを生成 vtimezone_component = Icalendar::Component.new('VTIMEZONE') vtimezone_component.custom_property('tzid', 'Asia/Tokyo') vtimezone_component.add(standard_component) cal.add(vtimezone_component) File.open("sample.ics", "w+b") { |f| f.write(cal.to_ical.toutf8) }
というかんじで、基本的なiCalendar形式のファイル(sample.ics)が生成されるんですが、
それをGoogle Calendarにインポートしてみたら、なぜか、時刻がうまくいきません。
そして、いろいろ試した結果、以下のようにしたら、できました。
iCalendarのサンプル改(Google Calendarでインポート可能)
require 'rubygems' require 'icalendar' require 'kconv' cal = Icalendar::Calendar.new # イベントを作成 cal.event do dtstart DateTime.new(2007, 07, 02, 10), {'TZID' => 'Asia/Tokyo'} # 変更箇所 dtend DateTime.new(2005, 07, 02, 20), {'TZID' => 'Asia/Tokyo'} # 変更箇所 summary "Meeting with the man." description "Have a long lunch meeting and decide nothing..." klass "PRIVATE" end # STANDARD コンポーネントを生成 standard_component = Icalendar::Component.new('STANDARD') standard_component.custom_property('dtstart', '19700101T000000') standard_component.custom_property('tzoffsetfrom', '+0900') standard_component.custom_property('tzoffsetto', '+0900') standard_component.custom_property('tzname', 'JST') # VTIMEZONE コンポーネントを生成 vtimezone_component = Icalendar::Component.new('VTIMEZONE') vtimezone_component.custom_property('tzid', 'Asia/Tokyo') vtimezone_component.add(standard_component) cal.add(vtimezone_component) File.open("sample.ics", "w+b") { |f| f.write(cal.to_ical.toutf8) }
という感じです。
どうもDTSTARTとDTENDにも、TZIDを設定することが重要なようです。
つまり、
DTSTART:20070702T100000 DTEND:20070702T200000
ではなく、
DTSTART;TZID=Asia/Tokyo:20070702T100000 DTEND;TZID=Asia/Tokyo:20070702T200000
となってないと、Google Calendarでは認識してくれないみたいです。