Ruby on rails 如何在Rails中转换原始时间字符串?

Ruby on rails 如何在Rails中转换原始时间字符串?,ruby-on-rails,ruby,Ruby On Rails,Ruby,在Rails(>=6)中,将表示时间的原始字符串转换为ActiveSupport::Duration对象的好方法是什么?例如,类似于: 45 min 1 h 我在中读到了一些答案,但问题是创业板不再被维护 module DurationParser class ParseError < StandardError; end # This is an example of how to extend it with aliases ALAISES = { hours:

在Rails(>=6)中,将表示时间的原始字符串转换为
ActiveSupport::Duration
对象的好方法是什么?例如,类似于:

45 min
1 h
我在中读到了一些答案,但问题是创业板不再被维护

module DurationParser
  class ParseError < StandardError; end
  # This is an example of how to extend it with aliases
  ALAISES = {
    hours: [:h, :hr],
    minutes: [:m, :min],
    seconds: [:s, :sec]
  }
  EXP = /^(?<value>[\d*|\.]*)\s*(?<token>\w*)?$/.freeze

  # Parses a human readable string into a duration
  # @example
  #   DurationParser.parse('2 hours, 1 minute')
  # @return [ActiveSupport::Duration]
  def self.parse(string)
    string.split(/and|,/).map(&:strip).map do |pair|
      matches = pair.match(EXP)
      method = token_to_method(matches[:token])
      raise ParseError unless method
      (matches[:value].to_i).send(method)
    end.reduce(&:+)
  end

  private
  def self.token_to_method(token)
    ActiveSupport::Duration::PARTS.find do |p|
      p == token.downcase.pluralize.to_sym
    end || ALAISES.find do |k,v|
      v.include?(token.downcase.to_sym)
    end&.first
  end
end


当然,如果您希望使用可靠的机器可读的东西,而不是不可靠的字符串解析器。

如果您可以确保字符串遵循特定格式,那么讨论中有一些答案不依赖gem。像这个还是这个。在您的情况下,您需要将当时的缩写转换为rails方法
h
->
.hours
等regex不是我的强大套件,因此这可能会简化。谢谢!事实上ISO8601将是伟大的,但我没有一手的数据
require 'rails_helper'

RSpec.describe DurationParser do
  describe '.parse' do
    it "handles hours" do
      expect(DurationParser.parse('1 h')).to eq 1.hour;
      expect(DurationParser.parse('1 hr')).to eq 1.hour;
      expect(DurationParser.parse('1 hour')).to eq 1.hour;
      expect(DurationParser.parse('3 hours')).to eq 3.hours;
    end
    it "handles minutes" do
      expect(DurationParser.parse('1 m')).to eq 1.minute;
      expect(DurationParser.parse('1 min')).to eq 1.minute;
      expect(DurationParser.parse('1 minute')).to eq 1.minute;
      expect(DurationParser.parse('2 minutes')).to eq 2.minutes;
    end
    it "handles seconds" do
      expect(DurationParser.parse('1 s')).to eq 1.second;
      expect(DurationParser.parse('1 sec')).to eq 1.second;
      expect(DurationParser.parse('1 second')).to eq 1.second;
      expect(DurationParser.parse('15 seconds')).to eq 15.seconds;
    end
    it "handles comma delimeted strings" do
      expect(DurationParser.parse('1 hour, 3 minutes, 15 seconds')).to eq(
        1.hour + 3.minutes + 15.seconds
      )
    end
    it "handles 'and' delimeted strings" do
      expect(DurationParser.parse('1 hour and 3 minutes and 15 seconds')).to eq(
        1.hour + 3.minutes + 15.seconds
      )
    end
    it "handles mixed delimeter strings" do
      expect(DurationParser.parse('1 hour and 3 minutes, 15 seconds')).to eq(
        1.hour + 3.minutes + 15.seconds
      )
    end
    it "raises when a bad token is passed" do
      expect { DurationParser.parse('25 sols') }.to raise_error(DurationParser::ParseError) 
    end
  end
end