如何使用用户的时区验证和解析 ISO 8601 时间戳?



我需要能够接收用户输入的时间戳,带有可选的时区组件,验证是否为有效的ISO 8601时间表示,并根据用户配置的时区对其进行解析。

我在Ruby 2.3上使用Rails 4.2.6。我曾希望Time.zoneActiveSupport::TimeZone)将具有与Time::iso8601等效的实现,这样我就可以挽救ArgumentError异常,以确定用户输入是否是有效的ISO8601时间表示。然后我可以做一些类似的事情:

user_time_zone = 'America/Los_Angeles' # Would actually be from user's stored settings
params = {when: '2016-04-01T01:01:01'} # Would actually be from user input
# Would actually use Time::use_zone in around_action filter
Time.use_zone(user_time_zone) do
  timestamp = Time.zone.iso8601 params[:when]
end

但是,唉,根本不存在这样的方法。我找不到同等的。

我不能使用Time.zone.parse,因为它将不明确的日期视为有效日期(例如Time.zone.parse '04/11/16' # => Tue, 16 Nov 0004 00:00:00 LMT -07:52)。

到目前为止,我能想出的最好的替代方案是:

Time.use_zone(user_time_zone) do
  old_tz = ENV['TZ']
  ENV['TZ'] = Time.zone.name
  timestamp = Time.iso8601 params[:when] # => 2016-04-01 01:01:01 -0700
  ENV['TZ'] = old_tz
end

但这很难看,以这种方式处理环境变量感觉不太合适,而且肯定不像Rails。如何以Rails的方式根据用户的时区验证和解析时间?

我建议您将赋值简单地分为两个步骤:首先验证ISO8601格式,如果有效,则解析它:

user_time_zone = 'America/Los_Angeles'
params = { when: '2016-04-01T01:01:01' }
begin
  Time.iso8601(params[:when])      # raises ArgumentError if format invalid
rescue ArgumentError => e
  puts "invalid time format" 
  return
end
Time.use_zone(user_time_zone) do
  timestamp = Time.zone.parse(params[:when])
end

我认为您仍然可以将around_action用于您的用例。这就是我使用的,对我来说效果很好。

在我的ApplicationController中,我有:

class ApplicationController < ActionController::Base  
  around_action :set_time_zone
  def set_time_zone
    old_time_zone = Time.zone
    Time.zone = user_time_zone
    yield
  ensure
    Time.zone = old_time_zone
  end
end

Time的任何调用都将使用请求范围内的用户时区。

相关内容

  • 没有找到相关文章

最新更新