Время назад в словах конвертируется в системную дату и время

Попытка преобразовать строки как 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'
Другие вопросы по тегам