web-dev-qa-db-ja.com

文字列が有効な日付であるかどうかを確認する方法

文字列があります:"31-02-2010"そして、それが有効な日付であるかどうかを確認したい。それを行う最良の方法は何ですか?

文字列が有効な日付である場合はtrueを返し、そうでない場合はfalseを返すメソッドが必要です。

103
Salil
require 'date'
begin
   Date.parse("31-02-2010")
rescue ArgumentError
   # handle invalid date
end
105
mpd

シンプルなライナーは次のとおりです。

DateTime.parse date rescue nil

呼び出し側にnilのチェックを強制するなど、実際のあらゆる状況でこれを正確に行うことはおそらくお勧めしません。特にフォーマット時。デフォルトの日付|エラーを返すと、より使いやすいかもしれません。

48
robert_murray
d, m, y = date_string.split '-'
Date.valid_date? y.to_i, m.to_i, d.to_i
48
Sohan

日付の解析は、特にそれらがMM/DD/YYYYまたはDD/MM/YYYY形式(米国やヨーロッパで使用される短い日付など)である場合、いくつかの落とし穴に陥ることがあります。

Date#parseはどちらを使用するかを判断しようとしますが、形式のあいまいさが構文解析の問題を引き起こす可能性がある年中、1か月に多くの日があります。

ユーザーのLOCALEを調べることをお勧めします。それから、Date.strptimeを使用してインテリジェントに解析する方法を知ることができます。ユーザーの居場所を見つける最良の方法は、サインアップ中にユーザーに尋ねてから、ユーザー設定で設定を変更して変更することです。あなたがいくつかの巧妙な発見的方法でそれを掘り出し、その情報をユーザーに迷惑をかけないと仮定すると、失敗しやすいので、ただ尋ねてください。

これはDate.parseを使用したテストです。私はアメリカにいます:

>> Date.parse('01/31/2001')
ArgumentError: invalid date

>> Date.parse('31/01/2001') #=> #<Date: 2001-01-31 (4903881/2,0,2299161)>

1つ目は、米国の正しい形式:mm/dd/yyyyでしたが、Dateはそれを好みませんでした。 2つ目はヨーロッパでは正しかったのですが、顧客が主に米国に拠点を置いている場合は、多くの不適切に解析された日付を取得します。

RubyのDate.strptimeは次のように使用されます。

>> Date.strptime('12/31/2001', '%m/%d/%Y') #=> #<Date: 2001-12-31 (4904549/2,0,2299161)>
28
the Tin Man

Date.valid_date? *date_string.split('-').reverse.map(&:to_i)

26
Samer Buna

Dateクラスを拡張したいと思います。

class Date
  def self.parsable?(string)
    begin
      parse(string)
      true
    rescue ArgumentError
      false
    end
  end
end

Date.parsable?("10-10-2010")
# => true
Date.parse("10-10-2010")
# => Sun, 10 Oct 2010
Date.parsable?("1")
# => false
Date.parse("1")
# ArgumentError: invalid date from (pry):106:in `parse'
9
ironsand

日付を検証する別の方法:

date_hash = Date._parse(date.to_s)
Date.valid_date?(date_hash[:year].to_i,
                 date_hash[:mon].to_i,
                 date_hash[:mday].to_i)
4
Slava Zharkov

すべての日付で正規表現を試してください:

/(\d{1,2}[-\/]\d{1,2}[-\/]\d{4})|(\d{4}[-\/]\d{1,2}[-\/]\d{1,2})/.match("31-02-2010")

先頭にゼロ、最後の年、ダッシュがある形式のみ:

/(\d{2}-\d{2}-\d{4})/.match("31-02-2010")

[-/]は-または/を意味し、スラッシュはエスケープする必要があります。これは http://gskinner.com/RegExr/ でテストできます

次の行を追加します。最初と最後の/なしで最初の正規表現を使用すると、すべて強調表示されます(Rubyコードで使用)。

2004-02-01
2004/02/01
01-02-2004
1-2-2004
2004-2-1
3
MrFox

より厳密なソリューション

期待する日付形式を指定すると、日付の正確さを確認するのが簡単です。しかし、それでも、Rubyは私のユースケースに対して少し寛容すぎます:

_Date.parse("Tue, 2017-01-17", "%a, %Y-%m-%d") # works
Date.parse("Wed, 2017-01-17", "%a, %Y-%m-%d") # works - !?
_

明らかに、これらの文字列の少なくとも1つは間違った曜日を指定していますが、Rubyはそれを喜んで無視します。

しないメソッドは次のとおりです。 date.strftime(format)が、formatに従って _Date.strptime_ で解析したのと同じ入力文字列に変換することを検証します。

_module StrictDateParsing
  # If given "Tue, 2017-01-17" and "%a, %Y-%m-%d", will return the parsed date.
  # If given "Wed, 2017-01-17" and "%a, %Y-%m-%d", will error because that's not
  # a Wednesday.
  def self.parse(input_string, format)
    date = Date.strptime(input_string, format)
    confirmation = date.strftime(format)
    if confirmation == input_string
      date
    else
      fail InvalidDate.new(
        "'#{input_string}' parsed as '#{format}' is inconsistent (eg, weekday doesn't match date)"
      )
    end
  end

  InvalidDate = Class.new(RuntimeError)
end
_
3
Nathan Long

後で誰かに役立つ可能性があるため、これを投稿します。これがそれを行うための「良い」方法であるかどうかはわかりませんが、それは私のために機能し、拡張可能です。

class String

  def is_date?
  temp = self.gsub(/[-.\/]/, '')
  ['%m%d%Y','%m%d%y','%M%D%Y','%M%D%y'].each do |f|
  begin
    return true if Date.strptime(temp, f)
      rescue
       #do nothing
    end
  end

  return false
 end
end

このStringクラスのアドオンを使用すると、行4で区切り文字のリストを指定し、行5で有効な形式のリストを指定できます。

"test".is_date?
"10-12-2010".is_date?
params[:some_field].is_date?
etc.
2
Dave Sanders

以下を試すことができますが、これは簡単な方法です:

"31-02-2010".try(:to_date)

ただし、例外を処理する必要があります。

0
Bruno Silva

この例では、Date.parseは例外を発生させません。

Date.parse("12!12*2012")
=> Thu, 12 Apr 2018

Date.parse("12!12&2012")
=> Thu, 12 Apr 2018

私はこの解決策を好む:

Date.parse("12!12*2012".gsub(/[^\d,\.,\-]/, ''))
=> ArgumentError: invalid date

Date.parse("12-12-2012".gsub(/[^\d,\.,\-]/, ''))
=> Wed, 12 Dec 2012

Date.parse("12.12.2012".gsub(/[^\d,\.,\-]/, ''))
=> Wed, 12 Dec 2012
0
Igor Biryukov
require 'date'
#new_date and old_date should be String
# Note we need a ()
def time_between(new_date, old_date)
  new_date = (Date.parse new_date rescue nil)
  old_date = (Date.parse old_date rescue nil)
  return nil if new_date.nil? || old_date.nil?
  (new_date - old_date).to_i
end

puts time_between(1,2).nil?
#=> true
puts time_between(Time.now.to_s,Time.now.to_s).nil?
#=> false
0
sander