コード日進月歩

しんくうの技術的な小話、メモ、つれづれ、など

Time.zone.nowを大量のくりかえしで使うときは一時保存しましょう

ゲームとかやってると割と当たり前なんだけど、そういうコードを見かけたので一応メモがてら。

環境

rails (5.2.0)

たとえばこんなコード

# 10日前のものを選出したい(whereしろというツッコミは忘れる)
User.all.each do |user|
  next if user.created_at < Time.zone.now - 10.days
  # なにか処理
  p user.id
end

このようなコードの場合、eachで回している間にTime.zone.nowが過ぎ去っていく可能性がある。

検証

ワンライナーでこんなコードを実行する

true_count=0;false_count = 0;t = Time.zone.now; 10000.times.each do |x| Time.zone.now.sec == t.sec ? true_count+=1 : false_count += 1 end

結果はこんな感じ

p "true_count:#{true_count} false_count:#{false_count}"
# "true_count:29741 false_count:70259"

Time.zone.nowが固定されていない事がわかる

対応

ループの外で固定化しましょう

target_time = Time.zone.now - 10.days
User.all.each do |user|
  next if user.created_at < target_time
  # なにか処理
  p user.id
end