Ruby: 列出日期时间格式选项

Ruby: List DateTime Format Options

我正在从 CSV 文件中导入数据,我想让我的用户指定 DateTime 列的格式。我没有让他们输入格式字符串并处理验证输入的痛苦,而是计划给他们一个 select 框,其中列出所有格式选项(例如 %m/%d/%Y,等等。 ..).有人提到 gem 已经存在,它将列出所有合理的 DateTime 格式,但我一直无法找到它。如何获取可用的日期时间格式列表以供显示?

查看 DateTime class。它是标准库的一部分,而不是外部 gem。您需要 require date 才能使用它。

以下是 irb 中的一些示例;请注意,使用 strftime 您有很大的灵活性,并且需要指定您自己的格式字符串。

2.3.0 :007 > dt = DateTime.now
 => #<DateTime: 2016-05-21T03:16:51+08:00 ((2457529j,69411s,139202000n),+28800s,2299161j)>
2.3.0 :008 > dt.iso8601
 => "2016-05-21T03:16:51+08:00"
2.3.0 :009 > dt.xmlschema
 => "2016-05-21T03:16:51+08:00"
2.3.0 :010 > dt.jisx0301
 => "H28.05.21T03:16:51+08:00"
2.3.0 :011 > dt.rfc3339
 => "2016-05-21T03:16:51+08:00"
2.3.0 :012 > dt.httpdate
 => "Fri, 20 May 2016 19:16:51 GMT"
2.3.0 :013 > dt.strftime('%Y-%m-%dT%H:%M:%S%z')
 => "2016-05-21T03:16:51+0800"

您可能对另一种选择感兴趣。不久前我不得不做类似的事情,并且支持几乎任意的日期格式。最后,我们从我们支持的所有数据源(CSV 文件)中检测到 29 种不同的格式(所有美国和加拿大国内)。

我想出了这个 class 来解析和缓存结果:

class DateParser
  @@date_cache = {}

  def self.is_date?(date)
    return self.match_digital_date?(date) || self.match_instance_date?(date)
  end

  def self.parse_date(date)
    return nil if date.blank?
    return date if date.instance_of?(Date)

    date = date.to_s
    cached_date = @@date_cache[date]

    return cached_date if !cached_date.nil?

    match = self.match_instance_date?(date)

    if !match.nil?
      month_str = match[1].upcase
      day = match[2].to_i
      year = match[3].to_i
      year += (year < 20) ? 2000 : 1900 if year < 1600

      month = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC'].find_index {|mon| mon == month_str }
      cached_date = Date.new(year, month+1, day) if !month.nil?
    else
      scrubbed_date = date.gsub(/^([0-9]+)[\/-]+([0-9]+)[\/-]+00$/, '\1/\2/2000')
      begin
        parsed = Chronic.parse(scrubbed_date)
      rescue
        parsed = nil
      end
      return nil if parsed.nil?

      cached_date = parsed.to_date
    end

    @@date_cache[date] = cached_date
    return cached_date
  end

private

  # Matches dates in these formats
  #  : 2015-01-13
  #  : 01-13-2015
  #  : 01-13-15
  #  : 13-01-15
  #  : 01/13/2015
  #  : 01/13/15
  #  : 13/01/15
  def self.match_digital_date?(date)
    return /^([0-9]+)[\/-]+([0-9]+)[\/-]+([0-9]+)$/.match(date)
  end

  def self.match_instance_date?(date)
    return /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d+)\/(\d+)/i.match(date)
  end
end

这使用 Chronic gem 进行一些日期解析,基于初始正则表达式匹配来选择解析路径,以及我们在此过程中遇到的一些必要的修正。正确性和速度是这种方法的主要目标。在大多数情况下,缓存结果有助于将 CSV 文件中的日期处理速度提高 5 倍或更多。

如果您想跳过询问用户他们使用的是哪种格式,而只是继续使用您选择的任何日期,这应该可以满足您的需求。