任意のタイムゾーンの任意の時刻を得る

タイトルわかりにくいな。要するに、例えばシカゴ時間の2014年11月17日午前7時を表すオブジェクトがほしいってこと。

ActiveSupport の in_time_zone と Time#utc_offset を使って作った。

# encoding: utf-8

require 'active_support/time'

def time_in_zone(timezone, year, month, day, hour = 0, min = 0, sec = 0)
  t = Time.new(year, month, day, hour, min, sec).utc
  now = Time.now
  offset1 = now.utc_offset
  offset2 = now.in_time_zone(timezone).utc_offset
  (t + offset1 - offset2).in_time_zone(timezone)
end

puts time_in_zone('America/Chicago', 2014, 11, 17, 7, 0, 0)
puts time_in_zone('Asia/Tokyo', 2014, 11, 17, 7, 0, 0)
takatoh@nightschool $ ruby time_in_zone.rb
2014-11-17 07:00:00 -0600
2014-11-17 07:00:00 +0900

なんかオフセットを足したり引いたりしてるところがややこしくて時間がかかった。もっとスマートな方法はないもんかな。

11/20追記

Time.new の7つ目の引数に、UTC からのオフセットを表す文字列を与えてやると、同じようなことができる。

2.1.1 :001 > Time.new(2014, 11, 17, 7, 0, 0, "-06:00")
 => 2014-11-17 07:00:00 -0600

問題は、オフセット文字列じゃなくてタイムゾーンの名前から作りたいってことだ。どうやったらいいだろう?