I want to get the timestamp for a table of locations in each rows' local timezone (stored in tz_name column).
Generalized, how does one have a dynamic sql call for the timestamp in a given timezone which is stored as a column in a postgres DB table.
Additionally, the time zone for a given location may be null, so a case statement is needed to handle a default timezone.
This query works fine:
locations=Location.select( Location.arel_table[:id], Arel::Nodes::Case.new .when( Location.arel_table[:tz_name].eq(nil)) .then('America/New_York') .else(Location.arel_table[:tz_name]).as("zone") , Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('hour'), Arel.sql("(select CURRENT_TIMESTAMP AT TIME ZONE'America/New_York')" ) ] ).as("now_hour") ).where( Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('hour'), Arel.sql("(select CURRENT_TIMESTAMP AT TIME ZONE'America/New_York')" ) ] ).eq(9)
However, when I try to use the case statement in the Arel.sql call, like so:
Arel.sql("(select CURRENT_TIMESTAMP AT TIME ZONE " + Arel::Nodes::Case.new .when( Location.arel_table[:tz_name].eq(nil)) .then('America/New_York') .else(Location.arel_table[:tz_name])+")" ) # fails in both cases
or move the Arel.sql into the case statement, like this:
Arel::Nodes::Case.new .when( Location.arel_table[:tz_name].eq(nil)) .then(Arel.sql("(select CURRENT_TIMESTAMP AT TIME ZONE 'America/New_York')")) #works .else(Arel.sql("(select CURRENT_TIMESTAMP AT TIME ZONE '#{Location.arel_table[:tz_name]}')")) #fails
It does not work.
How can I make the call for the timestamp with a Time Zone coming from the table column data ( location.tz_name )?
SolutionAs Max suggested below:
Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('hour'), Arel.sql("(TIMEZONE(COALESCE(locations.tz_name, 'America/New_York'), CURRENT_TIMESTAMP))") ] ).as("now_hour")