kanizaのブログ

コンピュータ、ソフトウェア、映画、音楽関連や家族のことなど、思いついたことを書きます。

iCalendarをCSVにするRubyスクリプト

どうやら、前に書いたRubyでiCalendarからCSVにする話によくアクセスがあるようだ。あの記事には具体的なスクリプトは書いていないから、せっかく来た人がっかりしてしまうんではないかと思い、Rubyスクリプトを載せてみることにする。ちょっと手直ししたけど、「えいや」で作ったスクリプトなので品質はご期待なきよう。Rubyも普段はぜんぜん書かないからヘタっぴいです。

前回の記事で書いたように、RubyGemsとiCalendarモジュールは入れておく。あとは、次のスクリプト内のホスト名とパスを正しく変更して実行すれば「開始日」「終了日」「開始時刻」「終了時刻」「概要」「場所」がコンマ区切りで出力される(それぞれ情報があればだけど)。ローカルのicsファイルから読み込むのもカンタンに変更できるはず。

(追記: 2007/7/20 ちょっとスクリプトをいじりました。動作自体は変更なしです)

#!/usr/bin/env ruby

# RubyGemsとiCalendarモジュールは入れておく
require 'rubygems'
require 'icalendar'

require 'date'
require 'iconv'
require 'net/http'
Net::HTTP.version_1_2 

$wdays = ['','','','','','',''];

# これ以前のイベントは無視する
basedate = Date.new(2006, 4, 1)

# ホスト名
cal_host = 'calendar.host.com'
# パス
cal_path = '/path/to/ical'

iconv = Iconv.new('Shift_JIS', 'UTF-8')

# 全日イベントかどうか
def full_day(event) 
  s = event.start
  e = event.end
  s != e && s.hour == 0 && s.min == 0 && e.hour == 0 && e.min == 0
end

# 複数日イベントかどうか
def multi_day(event)
  full_day(event) && (event.start + 1 != event.end)
end

def date_str(d)
  wday = $wdays[d.wday]
  "#{d.month}/#{d.day}(#{wday})"
end

def time_str(d)
  min = sprintf("%02d", d.min)
  "#{d.hour}:#{min}"
end

Net::HTTP.start( cal_host ) {|http|
  cals = Icalendar::parse(http.get(cal_path).body)
  cal = cals.first
  events = cal.events.sort {|a, b|
    a.dtstart <=> b.dtstart
  }
  events.each { |event|
    next if event.start < basedate 
    date = date_str(event.start)
    end_date = multi_day(event) ? date_str(event.end - 1) : ""
    start_time = full_day(event) ?  "" : time_str(event.start)
    end_time = full_day(event) ?  "" : time_str(event.end)
    location = iconv.iconv(event.location)
    summary = iconv.iconv(event.summary)
    print "#{date},#{end_date},#{start_time},#{end_time},#{summary},#{location}\n"
  }
}