2016-12-09 103 views
1

說明與日期時間字符串工作

我需要輸入一個字符串日期可與時區完整的日期 - 時間格式,它可能只是日期,也可能是24小時制只是時間,帶24小時制時區的時間,或上午和下午的時間或以上的任意組合。

作爲一個輸出,我想獲得當前(或給定)日期以24小時格式和時區,我們可以在ruby Time.parse()中解析時間。我做了一些工作,你可以在下面找到源代碼。我還爲一些期望添加了rspec(測試用例)。

你可以提供自己的解決方案或更新我的來源,只要你喜歡。

注:此處預產期是如果沒有提供日期

  1. '2200+5'應該得到轉化爲"2016-1-1T22:00:00 +0500"
  2. '100'應該轉換爲:"2016-1-1T01:00:00 +0000"
  3. 當前日期
  4. '1700+8'應該得到轉化爲"2016-1-1T17:00:00 +0800"
  5. '5pm+8'應該得到轉化爲"2016-1-1T17:00:00 +0800"
  6. '5am+8'應該得到轉化爲"2016-1-1T5:00:00 +0800"
  7. '2016-12-15T2300+5'應該轉換爲:'2016-12-15T23:00:00 +0500'
  8. '1730'應該轉換爲:"2016-1-1T17:30:00 +0000"
  9. '530pm+8'應該得到轉換到"2016-1-1T17:30:00 +0800"
  10. '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 

請讓我知道了進一步澄清。

感謝

+0

感謝您的建議,讓我這樣做 – przbadu

回答

1

此代碼工作正常你提到的例子,然後一些:

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 

它輸出:

16 examples, 0 failures 

如果你不想推倒重來,Chronic寶石可以幫助你,儘管它看起來像需要手動定義時區:Chronic.time_class = Time.zone

+0

感謝Eric的解決方案 – przbadu