よりシンプルに日付と時刻の表示書式を整えるには...
<%= user.updated_at %> 2008-08-08 04:52:49 UTC
- 以前に比べれば日本人にとっては分かり易い表示だが、決定的に問題なのは日本の時刻と9時間ずれていること。
タイムゾーン
- その環境を決めているのは、config/environment.rbの以下の部分。
- その部分をコメントアウトしてみると...
# ---------- config/environment.rb ---------- Rails::Initializer.run do |config| ...(中略)... config.time_zone = 'UTC' ...(中略)...
<%= user.updated_at %> Fri Aug 08 04:52:49 +0900 2008
- 書式が以前に戻った感じになり、相変わらず時刻はUTCだ。
- 今度はタイムゾーンに「Tokyo」を指定してみる。
# ---------- config/environment.rb ---------- Rails::Initializer.run do |config| ...(中略)... config.time_zone = 'Tokyo' ...(中略)...
<%= user.updated_at %> 2008-08-08 13:52:49 +0900
- おっ、日本の時刻で見易くなった!
- しかし、時刻表時の項目が多いとリストが横に長〜くなる。無駄に長い気がする。
strftimeで調整する
- strftimeで「+900」を取り除く。
<%= user.updated_at.strftime("%Y-%m-%d %H:%M:%S") %> 2008-08-08 13:52:49
- さらに2段表示にしてみる。
<%= user.updated_at.strftime("%Y-%m-%d<br />%H:%M:%S") %> 2008-08-08 13:52:49
- これで横幅は節約できるようになった!
ヘルパメソッドにする
- strftimeを繰り返すことになるのでヘルパに定義してみる。
# ---------- app/helpers/application_helper.rb ---------- module ApplicationHelper ...(中略)... def simple_time(time) time.strftime("%Y-%m-%d<br />%H:%M:%S") end ...(中略)...
- これで以下のように書ける。
<%= simple_time(user.updated_at) %> 2008-08-08 13:52:49
to_formatted_sメソッドを利用する
- 以前は上記で終わっていたが、最近、もっとシンプルな技を覚えた。
<%= user.updated_at.to_s(:db) %> 2008-08-08 13:52:49
- .to_s(:db)は.strftime("%Y-%m-%d %H:%M:%S")と同じ結果をもたらす。
- そして、以下のようにすることで、.to_s(フォーマット名)に独自のフォーマットを定義できる。
# ---------- config/environment.rb ---------- ...(中略)... Rails::Initializer.run do |config| ...(中略)... end # to_s(独自フォーマット)の定義 Time::DATE_FORMATS[:simple] = "%Y-%m-%d<br />%H:%M:%S"
- これで以下のように書けた!
<%= user.updated_at.to_s(:simple) %> 2008-08-08 13:52:49
左から順番にメソッドが実行されるところが、Rubyらしく、読み易くて好き。
APIマニュアルによると...
- http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Time/Conversions.html#M000278
- 設定は config/initializers/time_formats.rb にまとめちゃいましょうと。(ファイルを新規追加した。)
# ---------- config/initializers/time_formats.rb ---------- Time::DATE_FORMATS[:simple] = "%Y-%m-%d<br />%H:%M:%S"
- 最初から、以下の書式が定義されているようだ。
DATE_FORMATS = { :db => "%Y-%m-%d %H:%M:%S", :number => "%Y%m%d%H%M%S", :time => "%H:%M", :short => "%d %b %H:%M", :long => "%B %d, %Y %H:%M", :long_ordinal => lambda { |time| time.strftime("%B #{time.day.ordinalize}, %Y %H:%M") }, :rfc822 => "%a, %d %b %Y %H:%M:%S %z" }http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Time/Conversions.html#M000278
- lambdaを利用すれば、かなり自由な設定も可能だ!
タイムゾーンを設定する時、気になったこと
- Rails 2.1からはマイグレーションのバージョン管理にUTCを数字の羅列に変換したものを利用している。config.time_zone = 'Tokyo'としたら、バージョン管理の基準も変わってしまうのでは?
# ---------- app/controllers/users_controller.rb ---------- class UsersController < ApplicationController Time.zone = 'Tokyo' ...(中略)...
nilの問題
嬉しくなって.to_s(:simple)を使いまくっていると、問題発生!
- DBに日付や時刻でなくnilが保存されている場合、エラーが発生してしまった...。
>> nil.to_s(:simple) ArgumentError: wrong number of arguments (1 for 0)
- そのような場合、to_s(:simple)のフォーマット定義だけではどうしようもなく、利用する時にnilのチェックが必要になる。
<%= user.updated_at && user.updated_at.to_s(:simple) %>
- 一方、ヘルパメソッドsimple_timeなら、以下のようnilのチェックも簡単にラップすることができる。
# ---------- app/helpers/application_helper.rb ---------- module ApplicationHelper ...(中略)... def simple_time(time) time && time.strftime("%Y-%m-%d<br /><br />%H:%M:%S") end ...(中略)...
>> nil.to_s => ""
- それを実現するために、手っ取り早くapplication_helper.rbで以下のようにやってみたが...。
# ---------- app/helpers/application_helper.rb ---------- module ApplicationHelper ...(中略)... end class NilClass def to_s(*args) "" end end
- 一応、出来たが...。
>> nil.to_s(:simple) => ""
果たして、こんなことして良いのかな?という思い。どこかに悪い影響が出なければ良いのだが...。
- 以下の日記で、タイムゾーンの設定の仕方による挙動の変化も調べてみた。
- タイムゾーンはどのように設定しておこうか... - ザリガニが見ていた...。