【问题标题】:how to match the datetime format in rails如何匹配rails中的日期时间格式
【发布时间】:2018-08-10 07:34:43
【问题描述】:

我必须匹配控制器中的日期时间格式,如果格式不匹配,则拒绝请求。我一直在考虑做这样的事情

def datetime_range(from, to)
  raise ArgumentError if format_check
  (DateTime.parse(from))..(DateTime.parse(to))
end

但我不确定如何在不使用正则表达式的情况下匹配日期时间的格式。

【问题讨论】:

  • 你为什么不想使用正则表达式?
  • 您期望的格式是什么?什么价值观可以打破它?
  • 如果参数包含空、nil 或无效日期。然后它实际上就坏了。
  • empty 和 nil 可以使用present? 方法避免,但为了检查有效性,我想匹配格式。
  • 您要允许任何有效的日期格式还是特定的日期格式?因为在DateTime.parse('2018-08-20')DateTime.parse('20-08-2018') 中,格式不同但返回的日期(时间)相同。

标签: ruby-on-rails ruby datetime


【解决方案1】:

您可以在DateTime 类上使用strptime

DateTime.strptime(params[:datetime], allowed_format) 
# raises ArgumentError: invalid date if the string violates the format

控制器中的示例用法

class FooController < ApplicationController
  before_filter :parse_date

  def create
    # Do something with @date
  end

  private 

   def parse_date
     @date = DateTime.strptime(params[:date], '%Y-%m-%d')
   end
end

【讨论】:

  • 我遵循了你的 before_filter 方法,我正在使用 DateTime.parse
【解决方案2】:

在 Rails 中,您想使用 Time.zone.parse 正确处理时区。

我会用一个虚拟模型来处理这个任务。

# custom validator for dates
class DateValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value.try(:acts_like_time?) || value.try(:acts_like_date?)
      record.errors.add attribute, 'is not a valid date'
    end
  end
end

# call this whatever you want
class Query
  include ActiveModel::Model
  attr_accessor :from_date, :to_date

  validates :from_date, presence: true, date: true
  validates :to_date, presence: true, date: true

  def from_date=(value)
    @from_date = convert_to_time(value)
  end

  def to_date=(value)
    @to_date = convert_to_time(value)
  end

  def date_range
    @from_date..@to_date
  end

  private
    def convert_to_time(value)
      return value if value.try(:acts_like_time?)
      if value.try(:acts_like_string?)
        begin
          Time.zone.parse(value)
        rescue ArgumentError
          nil
        end
      end
    end
end

但您实际上并不需要重新发明处理日期属性和验证它们的轮子,因为有很多 gem 可以处理这些,例如 validates_timeliness

这可能看起来有点矫枉过正,但您可以像处理控制器中的任何资源一样处理它:

# this is just a simplefied example of filtering a resource
class FoosController < ApplicationController

  def index
    @foos = Foo.all 
    if query_attributes.any?
      @query = Query.new(query_attributes)
      if @query.valid?
        @foos = Foo.where(created_at: @query.date_range)
      else
        # do something else
      end
    end 
  end

  private
    def query_attributes
      params.fetch(:query)
            .permit(:from_date, :to_date)
    end
end

并将其与表单和 HTML5 日期助手一起使用:

<%= form_for @query || Query.new do |f| %>

  <% if @query.errors.any? %>
  <ul>
    <% @query.errors.full_messages.each do |m| %>
    <li><% m %></li>
    <% end %>
  </ul>
  <% end %>

  <div class="row">
    <%= f.label :from_date %>
    <%= f.date_select :from_date %>
  </div>

  <div class="row">
    <%= f.label :to_date %>
    <%= f.date_select :to_date %>
  </div>

  <%= f.submit %>
<% end %>

它还将逻辑保存在一个单独的域对象中,这很容易测试而不是膨胀控制器。

【讨论】:

    【解决方案3】:

    还有DateTime#iso8601方法。

    DateTime.iso8601('2018-08-10')
    #=> Fri, 10 Aug 2018 00:00:00 +0000
    
    DateTime.iso8601('2018-08-10T18:37')
    #=> Fri, 10 Aug 2018 18:37:00 +0000
    
    DateTime.iso8601('2018-08-10T18:37+02')
    #=> Fri, 10 Aug 2018 18:37:00 +0200
    
    DateTime.iso8601('2018-08-1018:37+02') # forgot T
    #=> ArgumentError: invalid date
    

    如果日期无效,此方法会引发ArgumentError,您可以从中挽救并提供错误。

    使用此方法时请记住,某些结果可能不是您所期望的:

    DateTime.iso8601('2017')
    #=> => Fri, 10 Aug 2018 20:17:00 +0000
    # Sets only the time to (20:17) but keeps the current day
    
    DateTime.iso8601('2017-11')
    #=> Wed, 11 Jan 2017 00:00:00 +0000
    # Set the year and the amount of days from start of year
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      • 2020-02-19
      • 2022-08-19
      相关资源
      最近更新 更多