Ruby 如何将简单的时间字符串解析为时间段?

Ruby 如何将简单的时间字符串解析为时间段?,ruby,datetime,Ruby,Datetime,在我的Ruby应用程序中,我有一个投资实体,它有一个术语属性 我需要这个类接受用户输入的字符串,格式为3年或36个月。然后,我想将输入转换为月数,将term属性设置为this period并计算到期日 到目前为止,我已经尝试使用主动支持和慢性支持,但API不支持这一点 此getter的工作原理是: def term if term =~ /year[s]?/i term = term.to_i * 12 else term =~ /month[s]?/i

在我的Ruby应用程序中,我有一个
投资
实体,它有一个
术语
属性

我需要这个类接受用户输入的字符串,格式为
3年
36个月
。然后,我想将输入转换为月数,将
term
属性设置为this period并计算到期日

到目前为止,我已经尝试使用主动支持和慢性支持,但API不支持这一点

此getter的工作原理是:

  def term
    if term =~ /year[s]?/i
      term = term.to_i * 12
    else term =~ /month[s]?/i
      term = term.to_i
    end
  end

但是在Ruby中有没有更优雅的方法来实现这一点呢?

如果我们可以假设输入字符串总是包含一个或多个数字,后跟一个单位(“年”、“年”、“月”等等),那么这是非常简单的。只需编写一个正则表达式,捕获数字和单位,将数字转换为数字并规范化单位,然后进行数学运算

def to_months(str)
  if str =~ /(\d+)\s*(month|year)s?/i
    num = $1.to_i      # => 3
    unit = $2.downcase # => year

    num *= 12 if unit == "year"
    return num
  end

  raise ArgumentError, "Invalid input"
end

puts to_months("3 Years") # => 36
puts to_months("1 month") # => 1
puts to_months("6months") # => 6

它并不比你的方法优雅多少,但也许它会给你一个或两个想法。

Ruby没有任何内置的表示“时间跨度”的东西(其他一些语言有)。然而,有一个问题,尽管这可能有点过分了你的情况

您提到,
chronic
不支持这一点。但是为什么不自己计算时差呢

require 'chronic'

input = '2 years'
then = Chronic.parse(input + ' ago')
now = Time.now

# Now we just calculate the number of months
term = (now.year * 12 + now.month) - (then.year * 12 + then.month)
这样,您就可以灵活地进行
慢性的
解析,并且仍然不需要太多的代码

或者直接使用
timespan

require 'timespan'

term = Timespan.new('2 years').to_months
# Boom.

听起来像是在试图解析向用户显示的标签,而不是向方法传递一个更容易计算的值。e、 g.在选择框中,选项标签可显示标签“3年”,但选项值应为整数36。因此,用户选择一个易于阅读的文本标签,但您将一个表示月数的整数传递给您的方法,这样就不需要解析字符串了。问得好!但如果这是唯一的需要,我对你的方法很在行。那么秒可能是你最好的选择。ChronicDuration可以将
3年
36个月
解析为秒。你会遇到这样一个问题,3年36个月是不一样的,这取决于你如何计算它@theTinMan:这就是为什么你不让他们破坏你的应用程序。您可以添加错误处理。不管您是否允许自由文本,您都需要它。@theTinMan:是的,显然您不想为应用程序中的每个输入表单定义DSL。在这种情况下,自由文本通常不适合使用。但在某些情况下,很难有一个好的UI,它的限制性足以避免歧义,但允许性足以不打扰用户(例如,向配方应用程序添加配料)。在这种情况下,一种选择是允许自由文本,以及一些(希望)健壮的解析,从而为用户提供所需的灵活性。不过,OP的情况可能并非如此。