Ho una stringa: "31-02-2010"
e voglio verificare se è una data valida o meno. Qual'è il miglior modo di farlo?
Ho bisogno di un metodo che restituisca true se la stringa è una data valida e false se non lo è.
Ho una stringa: "31-02-2010"
e voglio verificare se è una data valida o meno. Qual'è il miglior modo di farlo?
Ho bisogno di un metodo che restituisca true se la stringa è una data valida e false se non lo è.
Risposte:
require 'date'
begin
Date.parse("31-02-2010")
rescue ArgumentError
# handle invalid date
end
Ecco un semplice rivestimento:
DateTime.parse date rescue nil
Probabilmente non consiglierei di fare esattamente questo in ogni situazione nella vita reale poiché costringi il chiamante a verificare la presenza di zero, ad es. in particolare durante la formattazione. Se restituisci un errore di data predefinito, potrebbe essere più amichevole.
Date.strptime(date, '%d/%m/%Y') rescue nil
rescue
è sconsigliato.
d, m, y = date_string.split '-'
Date.valid_date? y.to_i, m.to_i, d.to_i
is_valid?
? Ho provato 1.8, 2.0 e 2.1. Nessuno di loro sembra averlo. Tutti sembrano esserlo valid_date?
, però.
L'analisi delle date può incorrere in alcuni trucchi, soprattutto quando sono in formato MM / GG / AAAA o GG / MM / AAAA, come le date brevi utilizzate negli Stati Uniti o in Europa.
Date#parse
tenta di capire quale usare, ma ci sono molti giorni in un mese durante l'anno in cui l'ambiguità tra i formati può causare problemi di analisi.
Consiglierei di scoprire qual è il LOCALE dell'utente, quindi, in base a questo, saprai come analizzare in modo intelligente utilizzando Date.strptime
. Il modo migliore per scoprire dove si trova un utente è chiederglielo durante la registrazione e quindi fornire un'impostazione nelle sue preferenze per modificarlo. Supponendo che tu possa estrarlo da qualche euristica intelligente e non disturbare l'utente per quelle informazioni, è incline al fallimento, quindi chiedi.
Questo è un test utilizzando Date.parse
. Sono negli Stati Uniti:
>> Date.parse('01/31/2001')
ArgumentError: invalid date
>> Date.parse('31/01/2001') #=> #<Date: 2001-01-31 (4903881/2,0,2299161)>
Il primo era il formato corretto per gli Stati Uniti: mm / gg / aaaa, ma la data non piaceva. Il secondo era corretto per l'Europa, ma se i tuoi clienti sono prevalentemente statunitensi, riceverai molte date mal analizzate.
Ruby's Date.strptime
è usato come:
>> Date.strptime('12/31/2001', '%m/%d/%Y') #=> #<Date: 2001-12-31 (4904549/2,0,2299161)>
01/01/2014
, qual è il mese e qual è il giorno? Negli Stati Uniti il mese sarebbe il primo, il resto del mondo sarebbe il secondo.
Date.valid_date? *date_string.split('-').reverse.map(&:to_i)
require "date"
prima o otterrai "metodo non definito".
Date.valid_date? *Array.new(3).zip(date_string.split('-')).transpose.last.reverse.map(&:to_i)
Mi piacerebbe estendere la Date
classe.
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'
Un altro modo per convalidare la data:
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)
Prova regex per tutte le date:
/(\d{1,2}[-\/]\d{1,2}[-\/]\d{4})|(\d{4}[-\/]\d{1,2}[-\/]\d{1,2})/.match("31-02-2010")
Solo per il formato con zeri iniziali, ultimo anno e trattini:
/(\d{2}-\d{2}-\d{4})/.match("31-02-2010")
il [- /] significa - o /, la barra deve essere preceduta da caratteri di escape. Puoi provarlo su http://gskinner.com/RegExr/
aggiungi le seguenti righe, saranno tutte evidenziate se usi la prima regex, senza la prima e l'ultima / (sono da usare nel codice ruby).
2004-02-01
2004/02/01
01-02-2004
1-2-2004
2004-2-1
32-13-2010
sbagliate.
'00/00/0000'
e '99-99/9999'
sono possibili candidati.
È più facile verificare la correttezza di una data se specifichi il formato della data previsto. Tuttavia, anche in questo caso, Ruby è un po 'troppo tollerante per il mio caso d'uso:
Date.parse("Tue, 2017-01-17", "%a, %Y-%m-%d") # works
Date.parse("Wed, 2017-01-17", "%a, %Y-%m-%d") # works - !?
Chiaramente, almeno una di queste stringhe specifica il giorno della settimana sbagliato, ma Ruby lo ignora felicemente.
Ecco un metodo che non lo fa; convalida la date.strftime(format)
riconversione nella stessa stringa di input con cui è stata analizzata in Date.strptime
base a format
.
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
Date.today().iso8601
); %m
è a riempimento zero. Se vuoi qualcosa di diverso, vedi ruby-doc.org/stdlib-2.4.0/libdoc/date/rdoc/…
Pubblicare questo perché potrebbe essere utile a qualcuno in seguito. Non ho idea se questo sia un modo "buono" per farlo o meno, ma per me funziona ed è estendibile.
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
Questo componente aggiuntivo per la classe String ti consente di specificare il tuo elenco di delimitatori nella riga 4 e quindi l'elenco dei formati validi nella riga 5. Non scienza missilistica, ma semplifica l'estensione e ti consente semplicemente di controllare una stringa in questo modo:
"test".is_date?
"10-12-2010".is_date?
params[:some_field].is_date?
etc.
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
Puoi provare quanto segue, che è il modo semplice:
"31-02-2010".try(:to_date)
Ma devi gestire l'eccezione.
Date.parse non sollevata eccezione per questi esempi:
Date.parse("12!12*2012")
=> Thu, 12 Apr 2018
Date.parse("12!12&2012")
=> Thu, 12 Apr 2018
Preferisco questa soluzione:
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
Metodo:
require 'date'
def is_date_valid?(d)
Date.valid_date? *"#{Date.strptime(d,"%m/%d/%Y")}".split('-').map(&:to_i) rescue nil
end
Uso:
config[:dates].split(",").all? { |x| is_date_valid?(x)}
Restituisce vero o falso se config [: date] = "12/10 / 2012,05 / 09/1520"