Railsとかに限った話じゃなくて、開発中のサーバー時刻を任意の時間に変更したいといったことはよくあると思う。
そうかの有名なアニメ、「時をかける少女」でいうタイムリープをしたいということである。
タイムリープする方法は
- アプリケーションの内部時刻を変更する
- アプリケーションが動いているサーバー自体の時刻を変更する
以上のような方法があげられるがサーバー自体の時刻を変更するなんて恐ろしすぎるし、かつめんどくさいのでアプリケーションの内部時刻を変更するアプローチで、Railsのサーバー時刻を変更できるようにしてみた
実装方法
時間を操作する際に、よく使うモジュールでTimecopというものがある。このTimecopのread meでrailsで使う場合の方法も書いてある
# in config/environments/test.rb config.after_initialize do # Set Time.now to September 1, 2008 10:05:00 AM (at this instant), but allow it to move forward t = Time.local(2008, 9, 1, 10, 5, 0) Timecop.travel(t) end read meより転載
と書かれていた。
例ではtest.rbで使うようにかいてあったけど、これをdevelopment.rbに書いてあげれば、developmentで起動しているときのみサーバー時間をいじれるはず。そこで以下のように書いてみた
# in config/environments/development.rb config.after_initialize do if File.exist?("tmp/localtime") then localtime = File.open("tmp/localtime").read if !localtime.blank? then t = Time.parse(localtime) Timecop.travel(t) end end end
tmp/localtime
というファイルをつくってその中にyyyy-mm-dd hh:mm:dd
形式で時間を書いて、その時間を読み取ってタイムリープするといったコードです。(あんまり設定ファイルにごちゃごちゃ書くのもあれなんで切り出したほうがよいかも)
このlocaltimeの設定はrakeタスクで行うようにしていて、
# in lib/tasks/server_time.rake namespace :server_time do task :mock => :environment do |t| set_time = ENV['RAILS_TIME'] File.open("tmp/localtime","w") do |file| file.puts(set_time) end end task :reset => :environment do File.unlink('tmp/localtime') end end
こんな感じに実装しました使い方はシンプルで
bundle exec rake server_time:mock RAILS_TIME='2016-01-01 00:00:00'
で設定して、bundle exec rake server_time:reset
でリセットできます。