を作ったので公開しました。Viewに
<p><%= select_datetime Time.now, { :include_timezone => true } %></p> <p><%= select_datetime Time.now, { :include_seconds => true, :include_timezone => true } %></p> <p><%= select_timezone %></p>
のように書くと、
といったフォームが表示され、入力された値はconfig/environment.rbで設定されたタイムゾーン等に従って適当に変換されます。
ActiveRecordとの連携はこれでいいのですが、検索とかに使う場合はコントローラ側で値を取りだしたくなります。そのためのメソッドが、get_multiparameter_attributes()とget_multiparameter_time()です。 get_multiparameter_attributes()は、Multiparameter attributeを配列に変換します。
% script/console Loading development environment (Rails 2.3.5) >> params = { ?> :datetime => { ?> "label(1i)" => "2010", "label(2i)" => "1", "label(3i)" => "1", ?> "label(4i)" => "0", "label(5i)" => "0", "label(6i)" => "0", ?> "label(7i)" => "+0900" >> } >> } => {:datetime=>{"label(3i)"=>"1", "label(4i)"=>"0", "label(5i)"=>"0", "label(6i)"=>"0", "label(7i)"=>"+0900", "label(1i)"=>"2010", "label(2i)"=>"1"}} >> ActionController::Base.new.get_multiparameter_attributes(params[:datetime], "label") => [2010, 1, 1, 0, 0, 0, 900]
また、get_multiparameter_attributes()はdatetimeに限らず任意の Multiparameter attributeを配列に変換できます。変換ルールはActiveRecord::Baseのtype_cast_attribute_valueメソッドに準拠しています。
>> input1 = { ?> "test(1i)" => "10", "test(2)" => "string", "test(3f)" => "3.14", "test(4i)" => "3.14", ?> "test(5i)" => "g", "test(6f)" => "g", "test(7i)" => "1g", "test(8f)" => "3.14g" >> } => {"test(8f)"=>"3.14g", "test(1i)"=>"10", "test(2)"=>"string", "test(4i)"=>"3.14", "test(7i)"=>"1g", "test(5i)"=>"g", "test(6f)"=>"g", "test(3f)"=>"3.14"} >> ActionController::Base.new.get_multiparameter_attributes(input1, "test") => [10, "string", 3.14, 3, 0, 0.0, 1, 3.14]
get_multiparameter_time()はより直接的に、View内のselect_datetimeなどから得られた入力をRailsのTime型に変換した物を取得します。
% script/console Loading development environment (Rails 2.3.5) >> params = { ?> :datetime => { ?> "label(1i)" => "2010", "label(2i)" => "1", "label(3i)" => "1", ?> "label(4i)" => "0", "label(5i)" => "0", "label(6i)" => "0", ?> "label(7i)" => "+0900" >> } >> } => {:datetime=>{"label(3i)"=>"1", "label(4i)"=>"0", "label(5i)"=>"0", "label(6i)"=>"0", "label(7i)"=>"+0900", "label(1i)"=>"2010", "label(2i)"=>"1"}} >> ActionController::Base.new.get_multiparameter_time(params[:datetime], "label") => Fri, 01 Jan 2010 00:00:00 JST +09:00
注意点として、これらを使ってデータベース内のタイムスタンプ等を検索する場合、得られたTime型の変数をデータベース内で保存されるタイムゾーンに変換する必要があります。手元のRails 2.3.5+sqlite3という環境ではRailsのconfig.time_zoneの設定によらず、データベースに対してはUTCで保存されていたので、findを掛けるときにutcメソッドで変換する必要がありました。
ts = get_multiparameter_time(params[:search_keys], "timestamp").utc Log.find(:first, :conditions => ["ip_addr = ? AND recorded_at <= ?", params[:search_keys][:ip], ts, :order => "recorded_at DESC")
UTC以外のタイムゾーンに変更する場合は、in_time_zoneメソッドを使用します。
ts = get_multiparameter_time(params[:search_keys], "timestamp").in_time_zone('Tokyo')
引数に指定可能なタイムゾーン名は"rake time:zones:all"で調べることができます。
選択フォームの代わりにテキストフィールドを使う場合、Viewで
<%= text_field "search_keys", "timestamp_text" %>
とやっておいて
ts = DateTime.parse(params[:search_keys][:timestamp_text]).utc