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

dep*_*uid 2 timezone ruby-on-rails iso8601

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

我在Ruby 2.3上使用Rails 4.2.6.我曾希望Time.zone(ActiveSupport::TimeZone)有一个等效的实现,Time::iso8601以便我可以挽救ArgumentError异常以确定用户输入是否是有效的ISO 8601时间表示.然后我可以这样做:

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
Run Code Online (Sandbox Code Playgroud)

但是,唉,不存在这样的方法.我找不到同等的一个.

我不能使用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
Run Code Online (Sandbox Code Playgroud)

但这很丑陋,用这种方式弄乱环境变量感觉不合适,而且肯定不是Rails.如何根据用户的时区以Rails方式验证和解析时间?

Bor*_*aMa 6

我建议您只需将分配分为两个步骤:首先验证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
Run Code Online (Sandbox Code Playgroud)