前一段时间用文字转换成系统日期时间

时间:2016-03-10 21:12:33

标签: ruby datetime sinatra

尝试将9 weeks ago1 year, 6 months ago20 hours ago等字符串转换为像Tue, 10 Mar 2015 12:06:15 PDT -07:00这样的红宝石时间对象。

我一直这样做:

eval("10 days ago".gsub(' ', '.'))

这样可以正常工作,但是像1 year, 6 months ago这样的字符串会爆炸。

我只需要进行比较,如:

eval("10 days ago".gsub(' ', '.')) < (Time.now - 7.days)

我使用 sinatra 所以没有花哨的铁路助手。

2 个答案:

答案 0 :(得分:1)

不言而喻,这很容易出错。使用风险由您自行承担:

def parse(date:)
  eval(date.gsub(/ ?(,|and) ?/, '+').tr(' ', '.').gsub(/^(.*)(\.ago)$/, '(\1)\2'))
end

parse(date: '1 year, 6 months ago') # => Wed, 10 Sep 2014 21:29:11 BST +01:00
parse(date: '1 year, 6 months, 3 weeks, 6 days, 9 hours and 12 seconds ago')
  # => Thu, 14 Aug 2014 12:33:07 BST +01:00

我们的想法是将原始字符串转换为:

'(1.year+6.months).ago'

答案 1 :(得分:1)

请勿在生产代码中使用eval ..

从转换 timeago表示法将非常复杂且资源密集。

但是,这种方式似乎最不容易出错:它会将“5秒前”之类的字符串转换为“5S”并使用mapping找到它及时的含义,之后它会减去那个时间从目前的时间。

解析字符串是动态构建的,因此它可以容纳大多数每个时间标记。

require('date')

mapping = {"D"=> "%d","W"=>"%U","H"=>"%T","Y"=>"%Y","M"=>"%m","S"=>"%S"}

timerel = "1 year, 6 months ago".split(",").map { |n| n.gsub(/\s+/, "").upcase()[0,2].split('')}

Date.strptime(
  timerel.map {|n| n[0]}.join(" "), 
  timerel.map {|n| mapping[n[1]]}.join(" ")
)

date = Date.new(0) + (Date.today - Date.strptime(timerel.map {|n| n[0]}.join(" "), timerel.map {|n| mapping[n[1]]}.join(" ")))

 => #<Date: 2014-10-10 ((2456941j,0s,0n),+0s,2299161j)>