webentwicklung-frage-antwort-db.com.de

So prüfen Sie, ob eine Zeichenfolge ein gültiges Datum ist

Ich habe eine Zeichenfolge: "31-02-2010" und möchte prüfen, ob es sich um ein gültiges Datum handelt .. Was ist der beste Weg, dies zu tun?

Ich brauche eine Methode, die true zurückgibt, wenn die Zeichenfolge ein gültiges Datum ist, und false, wenn dies nicht der Fall ist.

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

Hier ist ein einfacher Liner:

DateTime.parse date rescue nil

Ich würde wahrscheinlich nicht empfehlen, genau das in jeder Situation im wirklichen Leben zu tun, da Sie den Anrufer zwingen, auf Null zu prüfen, z. vor allem beim formatieren. Wenn Sie ein Standarddatum zurückgeben, ist es möglicherweise freundlicher.

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

Parsing-Daten können auf einige Gotchas zutreffen, insbesondere wenn sie im Format MM/TT/JJJJ oder DD/MM/YYYY vorliegen, wie z.

Date#parse versucht herauszufinden, welche Anwendung er verwenden soll. Es gibt jedoch viele Tage in einem Monat im Laufe des Jahres, an denen Mehrdeutigkeiten zwischen den Formaten zu Problemen bei der Analyse führen können.

Ich würde empfehlen, herauszufinden, was die LOCALE des Benutzers ist. Dann wissen Sie, wie Sie mit Date.strptime intelligent analysieren. Der beste Weg, um herauszufinden, wo sich ein Benutzer befindet, besteht darin, ihn während der Anmeldung zu fragen und dann in seinen Einstellungen eine Einstellung anzugeben, um diese zu ändern. Angenommen, Sie können es durch eine clevere Heuristik herausgreifen und den Benutzer für diese Informationen nicht stören, ist anfällig für Fehler, also fragen Sie einfach nach.

Dies ist ein Test mit Date.parse. Ich bin in den USA:

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

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

Das erste war das richtige Format für die USA: MM/TT/JJJJ, aber Date gefiel ihm nicht. Die zweite war für Europa richtig, aber wenn Ihre Kunden überwiegend in den USA ansässig sind, erhalten Sie viele schlecht geparste Daten.

Ruby's Date.strptime wird wie folgt verwendet:

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

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

26
Samer Buna

Ich möchte die Klasse Date erweitern.

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

beispiel

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'
8
ironsand

Eine andere Möglichkeit, das Datum zu bestätigen:

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)
3
Slava Zharkov

Regex für alle Termine testen:

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

Nur für Ihr Format mit führenden Nullen, letztem Jahr und Bindestrichen:

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

das [- /] bedeutet entweder - oder /, der Schrägstrich muss escape sein . Sie können dies unter http://gskinner.com/RegExr/ testen.

wenn Sie die folgenden Zeilen hinzufügen, werden sie alle hervorgehoben, wenn Sie den ersten regulären Ausdruck verwenden, ohne den ersten und letzten/(sie sind für die Verwendung in Ruby-Code bestimmt).

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

Eine strengere Lösung

Es ist einfacher, die Richtigkeit eines Datums zu überprüfen, wenn Sie das erwartete Datumsformat angeben. Trotzdem ist Ruby für meinen Anwendungsfall etwas zu tolerant:

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

Es ist klar, dass mindestens eine dieser Zeichenfolgen den falschen Wochentag angibt, aber Ruby ignoriert das gerne.

Hier ist eine Methode, die nicht funktioniert; Es bestätigt, dass date.strftime(format) wieder in dieselbe Eingabezeichenfolge konvertiert wird, die mit Date.strptime gemäß format analysiert wurde.

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

Das posten, weil es später für jemanden nützlich sein könnte. Keine Ahnung, ob dies ein "guter" Weg ist oder nicht, aber es funktioniert für mich und ist erweiterbar.

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

Mit diesem Add-On für die String-Klasse können Sie Ihre Liste mit Trennzeichen in Zeile 4 und dann Ihre Liste mit gültigen Formaten in Zeile 5 angeben. Das ist kein Hexenwerk, aber es ist wirklich einfach zu erweitern und Sie können einen String einfach so überprüfen:

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

Sie können Folgendes versuchen:

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

Sie müssen jedoch mit der Ausnahme umgehen.

0
Bruno Silva

Date.parse hat für diese Beispiele keine Ausnahme ausgelöst:

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

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

Ich bevorzuge diese Lösung:

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