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.
require 'date'
begin
Date.parse("31-02-2010")
rescue ArgumentError
# handle invalid date
end
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.
d, m, y = date_string.split '-'
Date.valid_date? y.to_i, m.to_i, d.to_i
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)>
Date.valid_date? *date_string.split('-').reverse.map(&:to_i)
Ich möchte die Klasse Date
erweitern.
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'
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)
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
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
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.
Sie können Folgendes versuchen:
"31-02-2010".try(:to_date)
Sie müssen jedoch mit der Ausnahme umgehen.
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
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