MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 その3

id:otn:20140829 の続き。


どういうときに、ExchangeのイベントとGoogle Calendarのイベントを等しいと判断するか。
考慮が必要なのは3点。

  • 文字列の内容

タイトル、内容、場所など文字列の文字コードがCP932か、utf-8かの違い。これはutf-8に揃えることにする。
また、内容がないときはExchangeは空文字列で、Google Calendarではnilで、これは空文字列に揃える。

  • 全日イベント

Exchangeだと0時から翌日0時の予定で、全日フラグ(AllDayEvent)がtrueになっている。
Google Calendarだと、日付だけが文字列でセットされている。これはExchange式に揃える。

  • リマインダー

Exchangeは、リマインダー有無のフラグ(ReminderSet)と、分数がセットされている。また、リマインダー時刻が過ぎると、分数はそのままでフラグがfalseになる。
Google Calendarは、複数のリマインダーがセットできるようで配列になっている。また、リマインダーのデフォルト値があり、デフォルトかどうかのフラグ(use_default)がある。リマインダーがないときは、デフォルトフラグがfalseで配列が空。リマインダー時刻が過ぎても値は変化しない。

class Event
  def ==(other)
    @start    == other.instance_variable_get(:@start)  and
    @end      == other.instance_variable_get(:@end)    and
    @allday   == other.instance_variable_get(:@allday) and
    reminder_eql?(@start, @reminder, other.instance_variable_get(:@reminder)) and
    @title    == other.instance_variable_get(:@title)  and
    @body     == other.instance_variable_get(:@body)   and
    @location == other.instance_variable_get(:@location)
  end
  private
  def reminder_eql?(start, x, y)
    @@now ||= Time.now
    ( x == y ) or
    ( x and not y and start - x < @@now ) or # リマインダー時刻を過ぎている場合はリマインダーの有無を無視
    ( y and not x and start - y < @@now )
  end
end

class Gcal < Event
  def initialize(event)
    if event.start.date # 全日イベント
      @start  = Time.parse(event.start.date)
      @end    = Time.parse(event.end.date)
      @allday = true
    else
      @start  = event.start.date_time
      @end    = event.end.date_time
      @allday = false
    end
    if event.reminders.use_default
      @reminder = 10 # 正確にはそのユーザーのデフォルト値を取得する必要がある
    elsif event.reminders.overrides[0]
      @reminder = event.reminders.overrides[0].minutes
    else
      @reminder = nil
    end
    @title = event.summary || ""
    @body  = event.description || ""
    @location = event.location || ""
    @id = event.id
  end
end

class Ecal < Evant
  def initialize(event)
    @start = event.Start
    @end   = event.End
    @allday = event.AllDayEvent
    @reminder = event.ReminderSet ? event.ReminderMinutesBeforeStart : nil
    @title  = event.Subject.encode(Encoding::UTF_8)
    @body   = event.Body.encode(Encoding::UTF_8)
    @location = event.Location.encode(Encoding::UTF_8)
  end
end