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

Railsのタイムゾーン

 Railsのタイムゾーン

D810cdc3c671ce77b11488e697807820?s=128

nobuhikosawai

March 24, 2018
Tweet

Transcript

  1. RailsͷλΠϜκʔϯ ᖒҪએ඙ (@nobuhikosawai) גࣜձࣾFiNC 2018/03/24 Rails Developers Meetup 2018: Day1εϙϯαʔτʔΫ

  2. ࠓ೔࿩͞ͳ͍͜ͱ • גࣜձࣾFiNCʹ͍ͭͯ • We are hiring 17:00͔ΒͷηογϣϯͰ@qsona͕࿩͢ͷͰͦͪΒ Λ͓ฉ͖Լ͍͞

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

    • ΤϯδχΞྺ: 2೥ • αʔόʔαΠυ(Rails) • ϑϩϯτΤϯυ(React.js)
  4. ࣗݾ঺հ • ೖࣾͨ͠࠷ॳͷϓϩ δΣΫτͰ͍͖ͳΓ ଟݴޠԽΛߦ͏
 => ϒϩάॻ͍ͨ 
 => ͪΐͬͱόζͬͨ

    https://goo.gl/AgGNoL
  5. ࣗݾ঺հ • ϥΠϒϥϦ(globalize)ͷ όάΛݟ͚ͭͯOSSʹ ߩݙ • ࣾ಺OSS׆ಈͷҰ؏Ͱ ग़ͨ͠΋ͷɻ
 ৄࡉ͸ͪ͜Βͷൃදʹ ৄ͍͠Ͱ͢ɻˣ


    https://www.slideshare.net/ ota42y/fincoss ଟݴޠԽΤϯδχΞ
  6. RailsͷλΠϜκʔϯʹ͍ͭͯ

  7. λΠϜκʔϯͱ͸ • ඪ४࣌: ͋Δࠃ΍޿͍஍Ҭ͕ڞ௨Ͱ࢖͏࣌ؒʢ೔ຊɺΞϝϦΧͷभʣ • λΠϜκʔϯ: ಉ͡ඪ४࣌Λ࢖͏஍ҬΛλΠϜκʔϯͱ͍͏ • 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)
  8. 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
  9. RailsͰλΠϜκʔϯΛऔΓѻ͏ํ๏ • ҧ͏λΠϜκʔϯΛऔΓѻ͍͍ͨͱ͖͸Ͳ͏ ͠Α͏ʁ

  10. 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
  11. 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>
  12. RailsͰλΠϜκʔϯΛऔΓѻ͏ํ๏ • ActiveSupport::TimeZone.new(9 * 3600) ͱ ActiveSupport::TimeZone.new(‘Asia/Tokyo’)͸ͲͪΒ΋ಉ͡Timezone ͕ฦͬͯ͘Δ • ͭ·ΓoffsetͰnewͯ͠΋ɺ࣮ࡏͷλΠϜκʔϯ͕ฦͬͯ͘Δɻ

  13. λΠϜκʔϯͱ͸ • αϚʔλΠϜ • Ն࣌ؒɺDST (daylight saving time) • Ң౓͕ߴ͘Նͷ೔র͕࣌ؒ௕͍஍ҬͰɺ໌Δ͍࣌ؒΛ༗ޮ׆༻͢

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

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

  16. ͕͜͜มͩΑRailsͷλΠϜκʔϯ • UTC -6 • America/ChicagoͳͲ͕͋Δ • શͯͷभͰαϚʔλΠϜ͕͋Δ
 • RailsͰ

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

    ‘America/Guatemara’) ͕ ώοτ͢ΔʢΞϝϦΧͷೆʹ͋Δผͷࠃʣ ΫΠζ2
  18. ͕͜͜มͩΑ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
  19. ͕͜͜มͩΑRailsͷλΠϜκʔϯ • ؒҧͬͨ΍ͭɺ͟·͊ΈΖʂ

  20. ͕͜͜มͩΑ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͕มΘͬͯͯࠔΔ
  21. ͕͜͜มͩΑRailsͷλΠϜκʔϯ • ͡Ό͋λΠϜκʔϯ໊Ͱຖճnew͢Δ͔͠ͳ͍ ͷ͔ʁʁ • ͍΍ɺͪΐͬͱ଴ͯʂ

  22. ͜ΕͰ͍͍ͷ͔RailsͷλΠϜκʔϯ • ੕࠲ΞϓϦΛ࡞ΔྫΛߟ͑Δ • rallsdm࠲͕ೆதͨ͠ΒpushΛૹΔ “ࠓ೔͸railsdmͰ͢ɻ” • rubykaigi࠲͕ೆதͨ͠ΒpushΛૹΔɻ”ࠓ೔͸rubykaigiͰ͢ɻ” • αʔόʔͰόονॲཧͰpushΛ͓͘Δ

    • αϚʔλΠϜΛߟྀ͢Δඞཁͳ͍ • offset͚ͩΘ͔ͬͯΕ͹͍͍ => offsetͰnew͍ͨ͠ʂ
  23. ͜ΕͰ͍͍ͷ͔RailsͷλΠϜκʔϯ • Javaʹ΋Swiftʹ΋TimeZone͸਺ࣈͰݻఆ͢Δػೳ͕͋Δ • Swift • secondsFromGMT • Java •

    ZonedDateTime • OffsetDateTime
  24. ͜ΕͰ͍͍ͷ͔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",
  25. ͜ΕͰ͍͍ͷ͔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
  26. ͜ΕͰ͍͍ͷ͔RailsͷλΠϜκʔϯ ࣮λΠϜκʔϯͷඞཁ͋Δʁʁ

  27. VirtualTimeZoneRails • ਺ࣈͰnewͨ͠ͱ͖͸࣮λΠϜκʔϯΛࢀর͠ͳ͍Α͏ʹ͢ ΔgemΛ࡞੒ͨ͠ https://github.com/nobuhikosawai/virtual_time_zone_rails

  28. 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
  29. VirtualTimeZoneRails gemͷ࡞Γํ • RailsʹPRૹΔͷ͸Ͱ͔͍ͷͰmonkey patchΛ౰ͯΔ • ΍ͬͨ͜ͱ͸େ͖͘2ͭ • ActiveSupport::TimeZoneͷnewΛ্ॻ͖ •

    newͨ͠ͱ͖ɺ࣮λΠϜκʔϯͰ͸ͳ͘Ծ૝తͳλΠϜ κʔϯVirtualTimeZoneΛఆٛͯͦ͠ΕΛฦ͢Α͏ʹ͢Δ
  30. VirtualTimeZoneRails • ActiveSupport::TimeZoneͷnewΛ্ॻ͖ • offsetͷͱ͖͚ͩͳͷͰଞͷڍಈ͸׬શʹطଘ ͷ··

  31. 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
  32. VirtualTimeZoneRails • ActiveSupport::TimeZoneͷΠϯελϯε͸಺ ෦ʹTZInfo::DataTimezoneΛอ͍࣋ͯ͠Δ ActiveSupport::TimeZone.new(‘Asia/Tokyo') # => #<ActiveSupport::TimeZone:0x00007fb455f642b0 @name="Asia/Tokyo", @tzinfo=#<TZInfo::DataTimezone:

    Asia/Tokyo>, @utc_offset=nil>
  33. VirtualTimeZoneRails • TZInfo::TimezoneΛܧঝͨ͠TZInfo::VirtualTimezoneΛఆٛ ܧঝؔ܎ - TZInfo::Timezone - InfoTimezone - DataTimezone

    ←λΠϜκʔϯ໊Ͱnew͢ΔͱฦΔ΍ͭ - LinkedTimezone - TimezoneProxy - VirtualTimezone ←ࠓճ௥Ճͨ͠Ϋϥε • TZInfo͸಺෦తʹ͸TimezonePeriodɺTimezoneOffsetΫϥε Λ༻͍ͯ࣌ࠩΛදݱ͍ͯ͠ΔͷͰɺ͜ΕΒΛݻఆͯ͠ฦ͢Α͏ ʹมߋ
  34. 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
  35. ࠓޙ • RailsʹIssue & PRૹ͍͖͍ͬͯͨͰ͢ • ࠓ͔ΒIssueͩ͠·͢·ͨ͠
 https://github.com/rails/rails/issues/32333

  36. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠