Время назад в словах конвертируется в системную дату и время
Попытка преобразовать строки как 9 weeks ago
, 1 year, 6 months ago
, 20 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)
Я использую Синатру, так что никаких навороченных помощников.
2 ответа
Пожалуйста, никогда не используйте 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)>
Само собой разумеется, что это очень подвержено ошибкам. Используйте на свой риск:
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'