Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

ࣗݾ঺հ • ໊લ: ᖒҪ એ඙
 ʢ͞Θ͍ ͷͿͻ͜ʣ • twitter/github: nobuhikosawai • ΤϯδχΞྺ: 2೥ • αʔόʔαΠυ(Rails) • ϑϩϯτΤϯυ(React.js)

Slide 4

Slide 4 text

ࣗݾ঺հ • ೖࣾͨ͠࠷ॳͷϓϩ δΣΫτͰ͍͖ͳΓ ଟݴޠԽΛߦ͏
 => ϒϩάॻ͍ͨ 
 => ͪΐͬͱόζͬͨ https://goo.gl/AgGNoL

Slide 5

Slide 5 text

ࣗݾ঺հ • ϥΠϒϥϦ(globalize)ͷ όάΛݟ͚ͭͯOSSʹ ߩݙ • ࣾ಺OSS׆ಈͷҰ؏Ͱ ग़ͨ͠΋ͷɻ
 ৄࡉ͸ͪ͜Βͷൃදʹ ৄ͍͠Ͱ͢ɻˣ
 https://www.slideshare.net/ ota42y/fincoss ଟݴޠԽΤϯδχΞ

Slide 6

Slide 6 text

RailsͷλΠϜκʔϯʹ͍ͭͯ

Slide 7

Slide 7 text

λΠϜκʔϯͱ͸ • ඪ४࣌: ͋Δࠃ΍޿͍஍Ҭ͕ڞ௨Ͱ࢖͏࣌ؒʢ೔ຊɺΞϝϦΧͷभʣ • λΠϜκʔϯ: ಉ͡ඪ४࣌Λ࢖͏஍ҬΛλΠϜκʔϯͱ͍͏ • 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)

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

RailsͰλΠϜκʔϯΛऔΓѻ͏ํ๏ • ҧ͏λΠϜκʔϯΛऔΓѻ͍͍ͨͱ͖͸Ͳ͏ ͠Α͏ʁ

Slide 10

Slide 10 text

RailsͰλΠϜκʔϯΛऔΓѻ͏ํ๏ • TimezoneͷऔΓѻ͍͸ActiveSupport::TimeZoneΫϥε͕ ߦ͍ͬͯΔɻ Time.zone # => #, @utc_offset=nil> ActiveSupport::TimeZone.new('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

Slide 11

Slide 11 text

RailsͰλΠϜκʔϯΛऔΓѻ͏ํ๏ • ActiveSupport::TimeZone͸offsetͷඵ਺Ͱ΋ newͰ͖Δ ActiveSupport::TimeZone.new(9 * 3600) # Asia/Tokyo # => #, @utc_offset=nil>

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

λΠϜκʔϯͱ͸ • αϚʔλΠϜ • Ն࣌ؒɺDST (daylight saving time) • Ң౓͕ߴ͘Նͷ೔র͕࣌ؒ௕͍஍ҬͰɺ໌Δ͍࣌ؒΛ༗ޮ׆༻͢ ΔͨΊʹಋೖ͞ΕΔ • य़ʹ1࣌ؒ͢͢Ίͯɺळʹ1࣌ؒ໭͢ɻ • railsͰ΋.dst?ͱ͍͏αϚʔλΠϜ൑ఆͷϝιου͕͋Δ • ಉ͡ࠃͰ΋஍ҬʹΑͬͯ͋ͬͨΓͳ͔ͬͨΓ͢Δ

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

͕͜͜มͩΑRailsͷλΠϜκʔϯ • UTC -7 • ਖ਼ղ͸false • Arizona͕ώοτ͢Δ ΫΠζ1

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

͕͜͜มͩΑRailsͷλΠϜκʔϯ • UTC -6 • ਖ਼ղ͸false
 • Central America ( ‘America/Guatemara’) ͕ ώοτ͢ΔʢΞϝϦΧͷೆʹ͋Δผͷࠃʣ ΫΠζ2

Slide 18

Slide 18 text

͕͜͜มͩΑRailsͷλΠϜκʔϯ ΫΠζ2 tz = ActiveSupport::TimeZone.new(-6 * 3600) #=> #, @utc_offset=nil> tz.local(2018, 8, 1).dst? #=> false

Slide 19

Slide 19 text

͕͜͜มͩΑRailsͷλΠϜκʔϯ • ؒҧͬͨ΍ͭɺ͟·͊ΈΖʂ

Slide 20

Slide 20 text

͕͜͜มͩΑRailsͷλΠϜκʔϯ tz = ActiveSupport::TimeZone.new(-5 * 3600) #-28800 #=> #, @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͕มΘͬͯͯࠔΔ

Slide 21

Slide 21 text

͕͜͜มͩΑRailsͷλΠϜκʔϯ • ͡Ό͋λΠϜκʔϯ໊Ͱຖճnew͢Δ͔͠ͳ͍ ͷ͔ʁʁ • ͍΍ɺͪΐͬͱ଴ͯʂ

Slide 22

Slide 22 text

͜ΕͰ͍͍ͷ͔RailsͷλΠϜκʔϯ • ੕࠲ΞϓϦΛ࡞ΔྫΛߟ͑Δ • rallsdm࠲͕ೆதͨ͠ΒpushΛૹΔ “ࠓ೔͸railsdmͰ͢ɻ” • rubykaigi࠲͕ೆதͨ͠ΒpushΛૹΔɻ”ࠓ೔͸rubykaigiͰ͢ɻ” • αʔόʔͰόονॲཧͰpushΛ͓͘Δ • αϚʔλΠϜΛߟྀ͢Δඞཁͳ͍ • offset͚ͩΘ͔ͬͯΕ͹͍͍ => offsetͰnew͍ͨ͠ʂ

Slide 23

Slide 23 text

͜ΕͰ͍͍ͷ͔RailsͷλΠϜκʔϯ • Javaʹ΋Swiftʹ΋TimeZone͸਺ࣈͰݻఆ͢Δػೳ͕͋Δ • Swift • secondsFromGMT • Java • ZonedDateTime • OffsetDateTime

Slide 24

Slide 24 text

͜ΕͰ͍͍ͷ͔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",

Slide 25

Slide 25 text

͜ΕͰ͍͍ͷ͔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

Slide 26

Slide 26 text

͜ΕͰ͍͍ͷ͔RailsͷλΠϜκʔϯ ࣮λΠϜκʔϯͷඞཁ͋Δʁʁ

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

VirtualTimeZoneRails • ਺ࣈͰnewͨ͠ͱ͖͸࣮λΠϜκʔϯΛࢀর͠ͳ͍Α͏ʹ͢ ΔgemΛ࡞੒ͨ͠ https://github.com/nobuhikosawai/virtual_time_zone_rails tz = ActiveSupport::TimeZone.new(9 * 3600) # => #, @utc_offset=nil> tz.local(2018, 8, 1) #=> Wed, 01 Aug 2018 00:00:00 VirtualTimeZone +09:00

Slide 29

Slide 29 text

VirtualTimeZoneRails gemͷ࡞Γํ • RailsʹPRૹΔͷ͸Ͱ͔͍ͷͰmonkey patchΛ౰ͯΔ • ΍ͬͨ͜ͱ͸େ͖͘2ͭ • ActiveSupport::TimeZoneͷnewΛ্ॻ͖ • newͨ͠ͱ͖ɺ࣮λΠϜκʔϯͰ͸ͳ͘Ծ૝తͳλΠϜ κʔϯVirtualTimeZoneΛఆٛͯͦ͠ΕΛฦ͢Α͏ʹ͢Δ

Slide 30

Slide 30 text

VirtualTimeZoneRails • ActiveSupport::TimeZoneͷnewΛ্ॻ͖ • offsetͷͱ͖͚ͩͳͷͰଞͷڍಈ͸׬શʹطଘ ͷ··

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

VirtualTimeZoneRails • ActiveSupport::TimeZoneͷΠϯελϯε͸಺ ෦ʹTZInfo::DataTimezoneΛอ͍࣋ͯ͠Δ ActiveSupport::TimeZone.new(‘Asia/Tokyo') # => #, @utc_offset=nil>

Slide 33

Slide 33 text

VirtualTimeZoneRails • TZInfo::TimezoneΛܧঝͨ͠TZInfo::VirtualTimezoneΛఆٛ ܧঝؔ܎ - TZInfo::Timezone - InfoTimezone - DataTimezone ←λΠϜκʔϯ໊Ͱnew͢ΔͱฦΔ΍ͭ - LinkedTimezone - TimezoneProxy - VirtualTimezone ←ࠓճ௥Ճͨ͠Ϋϥε • TZInfo͸಺෦తʹ͸TimezonePeriodɺTimezoneOffsetΫϥε Λ༻͍ͯ࣌ࠩΛදݱ͍ͯ͠ΔͷͰɺ͜ΕΒΛݻఆͯ͠ฦ͢Α͏ ʹมߋ

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

ࠓޙ • RailsʹIssue & PRૹ͍͖͍ͬͯͨͰ͢ • ࠓ͔ΒIssueͩ͠·͢·ͨ͠
 https://github.com/rails/rails/issues/32333

Slide 36

Slide 36 text

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