Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Railsのタイムゾーン

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

 Railsのタイムゾーン

Avatar for nobuhikosawai

nobuhikosawai

March 24, 2018
Tweet

More Decks by nobuhikosawai

Other Decks in Programming

Transcript

  1. ࣗݾ঺հ • ໊લ: ᖒҪ એ඙
 ʢ͞Θ͍ ͷͿͻ͜ʣ • twitter/github: nobuhikosawai

    • ΤϯδχΞྺ: 2೥ • αʔόʔαΠυ(Rails) • ϑϩϯτΤϯυ(React.js)
  2. λΠϜκʔϯͱ͸ • ඪ४࣌: ͋Δࠃ΍޿͍஍Ҭ͕ڞ௨Ͱ࢖͏࣌ؒʢ೔ຊɺΞϝϦΧͷभʣ • λΠϜκʔϯ: ಉ͡ඪ४࣌Λ࢖͏஍ҬΛλΠϜκʔϯͱ͍͏ • UTC: ڠఆੈք࣌ɻඪ४࣌Ͱ༻͍Δ࣌ࠁ͸ɺUTC͔ΒͷࠩͰදݱ͢Δ

    • Φϑηοτ: ͜ͷࠩ෼ͷ͜ͱΛoffsetʢ࣌ࠩʣͱݺͿ͜ͱ͕͋Δɻ https://ja.wikipedia.org/wiki/%E6%A8%99%E6%BA%96%E6%99%82
 https://ja.wikipedia.org/wiki/%E6%99%82%E9%96%93%E5%B8%AF_(%E6%A8%99%E6%BA%96%E6%99%82)
  3. RailsͰλΠϜκʔϯΛऔΓѻ͏ํ๏ • ActiveSupport::TimeWithZoneΛ࢖͏ͷ͕Ұൠతɻ
 ೔࣌ɺλΠϜκʔϯΛѻ͑ΔRailsಠࣗΫϥεɻ Time.zone.local(2018, 8, 1) # => Wed,

    01 Aug 2018 00:00:00 JST +09:00 • config/application.rbҎԼͷઃఆΛࢀর config.time_zone = ‘Asia/Tokyo' RubyͱRailsʹ͓͚ΔTime, Date, DateTime, TimeWithZoneͷҧ͍ - Qiita
  4. RailsͰλΠϜκʔϯΛऔΓѻ͏ํ๏ • TimezoneͷऔΓѻ͍͸ActiveSupport::TimeZoneΫϥε͕ ߦ͍ͬͯΔɻ Time.zone # => #<ActiveSupport::TimeZone:0x00007fb455f642b0 @name="Asia/ Tokyo",

    @tzinfo=#<TZInfo::DataTimezone: Asia/Tokyo>, @utc_offset=nil> ActiveSupport::TimeZone.new('Asia/Tokyo') #্͸͜Εͱಉ͡ # => #<ActiveSupport::TimeZone:0x00007fb455f642b0 @name="Asia/ Tokyo", @tzinfo=#<TZInfo::DataTimezone: Asia/Tokyo>, @utc_offset=nil> #ଞͷTimezoneΛࢦఆ ActiveSupport::TimeZone.new(‘America/New_York'). local(2018, 1, 1) # => Mon, 01 Jan 2018 00:00:00 EST -05:00
  5. RailsͰλΠϜκʔϯΛऔΓѻ͏ํ๏ • ActiveSupport::TimeZone͸offsetͷඵ਺Ͱ΋ newͰ͖Δ ActiveSupport::TimeZone.new(9 * 3600) # Asia/Tokyo #

    => #<ActiveSupport::TimeZone:0x00007fb454dbfb40 @name="Osaka", @tzinfo=#<TZInfo::DataTimezone: Asia/ Tokyo>, @utc_offset=nil>
  6. λΠϜκʔϯͱ͸ • αϚʔλΠϜ • Ն࣌ؒɺDST (daylight saving time) • Ң౓͕ߴ͘Նͷ೔র͕࣌ؒ௕͍஍ҬͰɺ໌Δ͍࣌ؒΛ༗ޮ׆༻͢

    ΔͨΊʹಋೖ͞ΕΔ • य़ʹ1࣌ؒ͢͢Ίͯɺळʹ1࣌ؒ໭͢ɻ • railsͰ΋.dst?ͱ͍͏αϚʔλΠϜ൑ఆͷϝιου͕͋Δ • ಉ͡ࠃͰ΋஍ҬʹΑͬͯ͋ͬͨΓͳ͔ͬͨΓ͢Δ
  7. ͕͜͜มͩΑRailsͷλΠϜκʔϯ • UTC -7 • America/Denver͸αϚʔλΠϜ͋Δ • America/Phoenix (Arizonaʣ
 ͸αϚʔλΠϜ͕ͳ͍

    • RailsͰtz = ActiveSupport::TimeZone.new(-7 * 3600) ͢ΔͱͲ͏ͳΔ ͔ʁ • tz.local(2018, 8, 1).dst? => true/false ͲͪΒͰ͠ΐ͏͔ʁ ΫΠζ1
  8. ͕͜͜มͩΑRailsͷλΠϜκʔϯ • UTC -6 • America/ChicagoͳͲ͕͋Δ • શͯͷभͰαϚʔλΠϜ͕͋Δ
 • RailsͰ

    tz = ActiveSupport::TimeZone.new(-6 * 3600) ͢ΔͱͲ͏ ͳΔ͔ʁ • tz.local(2018, 8, 1).dst? => true/false ͲͪΒͰ͠ΐ͏͔ʁ ΫΠζ2
  9. ͕͜͜มͩΑRailsͷλΠϜκʔϯ • UTC -6 • ਖ਼ղ͸false
 • Central America (

    ‘America/Guatemara’) ͕ ώοτ͢ΔʢΞϝϦΧͷೆʹ͋Δผͷࠃʣ ΫΠζ2
  10. ͕͜͜มͩΑRailsͷλΠϜκʔϯ ΫΠζ2 tz = ActiveSupport::TimeZone.new(-6 * 3600) #=> #<ActiveSupport::TimeZone:0x00007fb454db53e8 @name="Central

    America", @tzinfo=#<TZInfo::DataTimezone: America/ Guatemala>, @utc_offset=nil> tz.local(2018, 8, 1).dst? #=> false
  11. ͕͜͜มͩΑRailsͷλΠϜκʔϯ tz = ActiveSupport::TimeZone.new(-5 * 3600) #-28800 #=> #<ActiveSupport::TimeZone:0x00007fb4572b3460 @name="Pacific

    Time (US & Canada)", @tzinfo=#<TZInfo::DataTimezone: America/Los_Angeles>, @utc_offset=nil> tz.local(2018, 1, 1) #=> Mon, 01 Jan 2018 00:00:00 PST -08:00 tz.local(2018, 1, 1).utc_offset # => -28800 tz.local(2018, 8, 1) #=> Wed, 01 Aug 2018 00:00:00 PDT -07:00 tz.local(2018, 8, 1).utc_offset # => -25200 ʢ-28800Ͱnewͨ͠ͷʹʂʂʣ • উखʹoffset͕มΘͬͯͯࠔΔ
  12. ͜ΕͰ͍͍ͷ͔RailsͷλΠϜκʔϯ • RailsͰ͸ৗʹ࣮TimeZone͕औΓѻΘΕΔΑ͏ʹͳ͍ͬͯΔ • ಺෦ͰTimezoneͷhashΛ͍࣋ͬͯΔ class TimeZone # Keys are

    Rails TimeZone names, values are TZInfo identifiers. MAPPING = { "International Date Line West" => "Etc/GMT+12", "Midway Island" => "Pacific/Midway", "American Samoa" => "Pacific/Pago_Pago", "Hawaii" => "Pacific/Honolulu", "Alaska" => "America/Juneau", "Pacific Time (US & Canada)" => "America/Los_Angeles", "Tijuana" => "America/Tijuana",
  13. ͜ΕͰ͍͍ͷ͔RailsͷλΠϜκʔϯ hashΛϧʔϓͰճͯ͠ɺΘ͟Θ͟StringͰNumericͰ΋newͰ͖ΔΑ͏ʹ͍ͯ͠Δ def [](arg) case arg when String begin @lazy_zones_map[arg]

    ||= create(arg) rescue TZInfo::InvalidTimezoneIdentifier nil end when Numeric, ActiveSupport::Duration # ←͜͜ arg *= 3600 if arg.abs <= 13 all.find { |z| z.utc_offset == arg.to_i } else raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}" end end https://github.com/rails/rails/blob/db8cce202b8e81154773e5195a3ae35e873427e6/ activesupport/lib/active_support/values/time_zone.rb#L229
  14. VirtualTimeZoneRails • ਺ࣈͰnewͨ͠ͱ͖͸࣮λΠϜκʔϯΛࢀর͠ͳ͍Α͏ʹ͢ ΔgemΛ࡞੒ͨ͠ https://github.com/nobuhikosawai/virtual_time_zone_rails tz = ActiveSupport::TimeZone.new(9 * 3600)

    # => #<ActiveSupport::TimeZone:0x007ff3dab57e50 @name="secondsFromGMT#32400", @tzinfo=#<TZInfo::VirtualTimezone: secondsFromGMT#32400>, @utc_offset=nil> tz.local(2018, 8, 1) #=> Wed, 01 Aug 2018 00:00:00 VirtualTimeZone +09:00
  15. VirtualTimeZoneRails gemͷ࡞Γํ • RailsʹPRૹΔͷ͸Ͱ͔͍ͷͰmonkey patchΛ౰ͯΔ • ΍ͬͨ͜ͱ͸େ͖͘2ͭ • ActiveSupport::TimeZoneͷnewΛ্ॻ͖ •

    newͨ͠ͱ͖ɺ࣮λΠϜκʔϯͰ͸ͳ͘Ծ૝తͳλΠϜ κʔϯVirtualTimeZoneΛఆٛͯͦ͠ΕΛฦ͢Α͏ʹ͢Δ
  16. VirtualTimeZoneRails require 'tzinfo/virtual_timezone' require 'active_support/values/time_zone' ActiveSupport::TimeZone.class_eval do class << self

    alias_method :square_brackets, :[] def [](arg) case arg when Numeric, ActiveSupport::Duration # ←্͚ͩ͜͜ॻ͖ tzinfo = TZInfo::VirtualTimezone.new(arg) @lazy_zones_map[arg] ||= create(tzinfo.name, nil, tzinfo) else square_brackets(arg) end end end end
  17. VirtualTimeZoneRails • TZInfo::TimezoneΛܧঝͨ͠TZInfo::VirtualTimezoneΛఆٛ ܧঝؔ܎ - TZInfo::Timezone - InfoTimezone - DataTimezone

    ←λΠϜκʔϯ໊Ͱnew͢ΔͱฦΔ΍ͭ - LinkedTimezone - TimezoneProxy - VirtualTimezone ←ࠓճ௥Ճͨ͠Ϋϥε • TZInfo͸಺෦తʹ͸TimezonePeriodɺTimezoneOffsetΫϥε Λ༻͍ͯ࣌ࠩΛදݱ͍ͯ͠ΔͷͰɺ͜ΕΒΛݻఆͯ͠ฦ͢Α͏ ʹมߋ
  18. VirtualTimeZoneRails module TZInfo class VirtualTimezone < Timezone def self.new(seconds_from_gmt) vt

    = super() vt.send(:setup, seconds_from_gmt) vt end # Returns the TimezonePeriod based on the given seconds from GMT. def period_for_utc(_utc) TimezonePeriod.new(nil, nil, @offset) end ... private def setup(seconds_from_gmt) @seconds_from_gmt = seconds_from_gmt @offset = TimezoneOffset.new(@seconds_from_gmt, 0, :VirtualTimeZone) end end end