Ruby on rails 使用日期时间字符串

Ruby on rails 使用日期时间字符串,ruby-on-rails,ruby,date,datetime,rspec,Ruby On Rails,Ruby,Date,Datetime,Rspec,说明 我需要得到一个字符串日期输入,可以是完整的日期时间格式和时区,它可以是日期,它可以是24小时格式的时间,时间与时区在24小时格式,或时间在上午和下午或以上任何组合 作为一个输出,我想得到24小时格式的当前(或给定)日期和时间以及一个时区,我们可以在rubytime.parse()中解析它。我已经做了一些工作,你可以在下面找到源代码。我还为一些期望添加了rspec(测试用例) 您可以提供自己的解决方案,也可以根据需要更新我的源代码 示例 注:如果未提供日期,此处预期日期为当前日期 “2200

说明

我需要得到一个字符串日期输入,可以是完整的日期时间格式和时区,它可以是日期,它可以是24小时格式的时间,时间与时区在24小时格式,或时间在上午和下午或以上任何组合

作为一个输出,我想得到24小时格式的当前(或给定)日期和时间以及一个时区,我们可以在ruby
time.parse()中解析它。我已经做了一些工作,你可以在下面找到源代码。我还为一些期望添加了rspec(测试用例)

您可以提供自己的解决方案,也可以根据需要更新我的源代码

示例

注:如果未提供日期,此处预期日期为当前日期

  • “2200+5”
    应转换为
    “2016-1-1T22:00:00+0500”
  • '100'
    应转换为
    “2016-1-1T01:00:00+0000”
  • “1700+8”
    应转换为
    “2016-1-1T17:00:00+0800”
  • '5pm+8'
    应转换为
    “2016-1-1T17:00:00+0800”
  • '5am+8'
    应转换为
    “2016-1-1T5:00:00+0800”
  • '2016-12-15T2300+5'
    应转换为
    '2016-12-15T23:00:00+0500'
  • '1730'
    应转换为
    “2016-1-1T17:30:00+0000”
  • '530pm+8'
    应转换为
    “2016-1-1T17:30:00+0800”
  • '1210am+8'
    应转换为
    “2016-1-1T12:10:00+0800”
  • RSpec

    describe "should convert datetime to accepted format"
        Timecop.freeze(Time.utc(2016,1,1,2,0,0))
        it {expect(parse('2200+5')).to eq({time: Time.parse("2016-1-1T22:00:00 +0500")})}
        it {expect(parse('100')).to eq({time: Time.parse("2016-1-1T01:00:00 +0000")})}
        it {expect(parse('1700+8')).to eq({time: Time.parse("2016-1-1T17:00:00 +0800")})}
        it {expect(parse('5pm+8')).to eq({time: Time.parse("2016-1-1T17:00:00 +0800")})}
        it {expect(parse('5am+8')).to eq({time: Time.parse("2016-1-1T5:00:00 +0800")})}
        it {expect(parse('2016-12-15T2300+5')).to eq({time: Time.parse("2016-12-15T23:00:00 +0500")})}
        it {expect(parse('1730')).to eq({time: Time.parse("2016-1-1T17:30:00 +0000")})}
        Timecop.return
    end
    
    我到目前为止所做的事情

    # ensure 2 char in time format
    def ensure_2_char_in_time(t)
      return "0#{t}" if t.to_s.length == 1
      t.to_s
    end
    
    
    def get_time_zone_from(aTimeParams)
      date, tzm, tzm_type = nil
    
      # get date, time, timezon from given string
      if aTimeParams.include?('-') && aTimeParams.include?('T')
          date, time_zone = aTimeParams.split('T')
      else
        time_zone = aTimeParams
      end
    
      # get time, zone from given string
      if time_zone.include?('+')
        tzm_type = '+'
        time_str, tzm = aTimeParams.split('+')
      elsif time_zone.include?('-')
        tzm_type = '-'
        time_str, tzm = aTimeParams.split('-')
      else
        tzm_type = '+'
        time_str = aTimeParams
      end
      date = "#{Date.today.year}-#{Date.today.month}-#{Date.today.day}" if date.blank?
    
      if time_str.include?('pm')
          hour = ensure_2_char_in_time(time_str.to_i + 12)
          min = '00'
      elsif time_str.include?('am')
        hour = ensure_2_char_in_time(time_str.to_i)
        min = '00'
      else
        hour = ensure_2_char_in_time(time_str.to_i / 100)
        min = ensure_2_char_in_time(time_str.to_i % 100)
      end
    
      if tzm.to_s.length <= 2
        tzm_h = ensure_2_char_in_time tzm.to_i % 100
        tzm_m = "00"
      else
        tzm_h = ensure_2_char_in_time tzm.to_i / 100
        tzm_m = ensure_2_char_in_time tzm.to_i % 100
      end
    
      {
          time: Time.parse("#{date}T#{hour}:#{min}:00 #{tzm_type}#{tzm_h}:#{tzm_m}"),
          tzm: (tzm_h.to_i * 60 + tzm_m.to_i)
      }
    end
    
    #确保时间格式为2个字符
    def确保字符输入时间(t)
    如果t.to_.length==1,则返回“0{t}”
    t、 到
    结束
    def get_time_zone_from(aTimeParams)
    日期,tzm,tzm_类型=零
    #从给定字符串获取日期、时间、时区
    如果aTimeParams.include('-')&aTimeParams.include('T'))
    日期、时区=aTimeParams.split('T')
    其他的
    时区=aTimeParams
    结束
    #从给定字符串中获取时间、区域
    如果时区。包括?(“+”)
    tzm_类型='+'
    time_str,tzm=aTimeParams.split(+)
    elsif时区。包括?(“-”)
    tzm_类型='-'
    time_str,tzm=aTimeParams.split('-'))
    其他的
    tzm_类型='+'
    时间=时间参数
    结束
    date=“#{date.today.year}-#{date.today.month}-#{date.today.day}”如果date.blank?
    如果时间包括('pm')
    小时=确保字符在时间内(时间长度至i+12)
    最小值='00'
    elsif时间段包括('am')
    小时=确保字符在时间内(时间长度到时间)
    最小值='00'
    其他的
    小时=确保字符输入时间(时间长度至i/100)
    最小值=确保字符在时间内(时间长度为100)
    结束
    
    如果tzm.to_.length此代码适用于您提到的示例,然后是一些:

    module FuzzyTimeParse
      refine String do
        # Removes the first regex match from self.
        # Returns the matching substring if found, nil otherwise
        def extract!(regex)
          sub!(regex, '')
          $&
        end
      end
    
      refine Time.singleton_class do
        def fuzzy_parse(date_or_time_or_something)
          input = date_or_time_or_something.dup
    
          input.extract!('am')
          pm = input.extract!('pm') ? 12 : 0
    
          timezone = input.extract!(/\s*(\+|-)\d$/).to_f || 0
    
          timezone_hour = timezone.to_i
          timezone_min  = timezone * 60 % 60
    
          if hour = input.extract!(/(?<![\d\:\-])\d\d?$/)
            min   = 0
          else
            min   = input.extract!(/(?<!-)\d\d$/) || 0
            input.extract!(':')
            hour  = input.extract!(/(?<![-\d])\d\d?$/) || 0
          end
    
          input.extract!(/T$/)
          input.gsub!(/\s*/,'')
          date = input.extract!(/\d\d\d\d\D?\d\d\D?\d\d/) || Time.now.strftime('%Y-%m-%d')
    
          $stderr.puts "Warning : #{input} is still not parsed" unless input.empty?
          date_time = format('%sT%02d:%02d:00 +%02d%02d', date, hour.to_i + pm, min, timezone_hour, timezone_min)
    
          { time: Time.parse(date_time) }
        end
      end
    end
    
    require 'timecop'
    
    using FuzzyTimeParse
    
    describe 'convert datetime to accepted format' do
      before do
        Timecop.freeze(Time.local(2016, 1, 1, 2, 0, 0))
      end
    
      it { expect(Time.fuzzy_parse('2200+5')).to eq(time: Time.parse('2016-1-1T22:00:00 +0500')) }
      it { expect(Time.fuzzy_parse('100')).to eq(time: Time.parse('2016-1-1T01:00:00 +0000')) }
      it { expect(Time.fuzzy_parse('1700+8')).to eq(time: Time.parse('2016-1-1T17:00:00 +0800')) }
      it { expect(Time.fuzzy_parse('5pm+8')).to eq(time: Time.parse('2016-1-1T17:00:00 +0800')) }
      it { expect(Time.fuzzy_parse('5am+8')).to eq(time: Time.parse('2016-1-1T5:00:00 +0800')) }
      it { expect(Time.fuzzy_parse('2016-12-15T2300+5')).to eq(time: Time.parse('2016-12-15T23:00:00 +0500')) }
      it { expect(Time.fuzzy_parse('2016-12-15 2300')).to eq(time: Time.parse('2016-12-15T23:00:00 +0000')) }
      it { expect(Time.fuzzy_parse('2016-12-15 23:10 +7')).to eq(time: Time.parse('2016-12-15T23:10:00 +0700')) }
      it { expect(Time.fuzzy_parse('1730')).to eq(time: Time.parse('2016-1-1T17:30:00 +0000')) }
      it { expect(Time.fuzzy_parse('1210am+8')).to eq(time: Time.parse('2016-1-1T12:10:00 +0800')) }
      it { expect(Time.fuzzy_parse('530pm+8')).to eq(time: Time.parse('2016-1-1T17:30:00 +0800')) }
      it { expect(Time.fuzzy_parse('1730')).to eq(time: Time.parse('2016-1-1T17:30:00 +0000')) }
      it { expect(Time.fuzzy_parse('17:30')).to eq(time: Time.parse('2016-1-1T17:30:00 +0000')) }
      it { expect(Time.fuzzy_parse('17:30 +5')).to eq(time: Time.parse('2016-1-1T17:30:00 +0500')) }
      it { expect(Time.fuzzy_parse('2016-12-03')).to eq(time: Time.parse('2016-12-03T00:00:00 +0000')) }
      it { expect(Time.fuzzy_parse('2016-12-03 +2')).to eq(time: Time.parse('2016-12-03T00:00:00 +0200')) }
    
      after do
        Timecop.return
      end
    end
    

    如果您不想重新发明轮子,gem可以帮助您,尽管它看起来需要手动定义时区:
    Chronic.time\u class=time.zone

    谢谢您的建议,让我来做吧谢谢Eric的解决方案
    16 examples, 0 failures