J'ai une chaîne: "31-02-2010"
et je veux vérifier si c'est une date valide ou non. Quelle est la meilleure façon de procéder?
J'ai besoin d'une méthode qui renvoie true si la chaîne est une date valide et false si ce n'est pas le cas.
J'ai une chaîne: "31-02-2010"
et je veux vérifier si c'est une date valide ou non. Quelle est la meilleure façon de procéder?
J'ai besoin d'une méthode qui renvoie true si la chaîne est une date valide et false si ce n'est pas le cas.
Réponses:
require 'date'
begin
Date.parse("31-02-2010")
rescue ArgumentError
# handle invalid date
end
Voici une simple doublure:
DateTime.parse date rescue nil
Je ne recommanderais probablement pas de faire exactement cela dans toutes les situations de la vie réelle, car vous forcez l'appelant à vérifier zéro, par exemple. en particulier lors du formatage. Si vous renvoyez une date par défaut | erreur, cela peut être plus convivial.
Date.strptime(date, '%d/%m/%Y') rescue nil
rescue
est déconseillée.
d, m, y = date_string.split '-'
Date.valid_date? y.to_i, m.to_i, d.to_i
is_valid?
? Essayé 1.8, 2.0 et 2.1. Aucun d'entre eux ne semble avoir celui-là. valid_date?
Mais tout semble l'avoir fait .
L'analyse des dates peut se heurter à certains pièges, en particulier lorsqu'elles sont au format MM / JJ / AAAA ou JJ / MM / AAAA, comme les dates courtes utilisées aux États-Unis ou en Europe.
Date#parse
tente de déterminer lequel utiliser, mais il y a plusieurs jours dans un mois tout au long de l'année où l'ambiguïté entre les formats peut causer des problèmes d'analyse.
Je recommanderais de savoir quelle est la LOCALE de l'utilisateur, puis, sur cette base, vous saurez comment analyser intelligemment en utilisant Date.strptime
. La meilleure façon de trouver où se trouve un utilisateur est de lui demander lors de l'inscription, puis de fournir un paramètre dans ses préférences pour le modifier. En supposant que vous puissiez le découvrir par une heuristique intelligente et ne pas déranger l'utilisateur pour cette information, il est sujet à l'échec, alors demandez simplement.
Ceci est un test utilisant Date.parse
. Je suis aux USA:
>> Date.parse('01/31/2001')
ArgumentError: invalid date
>> Date.parse('31/01/2001') #=> #<Date: 2001-01-31 (4903881/2,0,2299161)>
Le premier était le format correct pour les États-Unis: mm / jj / aaaa, mais Date ne l'aimait pas. La seconde était correcte pour l'Europe, mais si vos clients sont principalement basés aux États-Unis, vous obtiendrez beaucoup de dates mal analysées.
Ruby Date.strptime
est utilisé comme:
>> Date.strptime('12/31/2001', '%m/%d/%Y') #=> #<Date: 2001-12-31 (4904549/2,0,2299161)>
01/01/2014
, quel est le mois et quel est le jour? Le mois américain serait le premier, le reste du monde serait le deuxième.
Date.valid_date? *date_string.split('-').reverse.map(&:to_i)
require "date"
abord ou vous obtiendrez "méthode non définie".
Date.valid_date? *Array.new(3).zip(date_string.split('-')).transpose.last.reverse.map(&:to_i)
J'aimerais prolonger 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'
Une autre façon de valider la date:
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)
Essayez regex pour toutes les dates:
/(\d{1,2}[-\/]\d{1,2}[-\/]\d{4})|(\d{4}[-\/]\d{1,2}[-\/]\d{1,2})/.match("31-02-2010")
Pour uniquement votre format avec des zéros non significatifs, l'année dernière et des tirets:
/(\d{2}-\d{2}-\d{4})/.match("31-02-2010")
le [- /] signifie soit - soit /, la barre oblique doit être échappée. Vous pouvez tester ceci sur http://gskinner.com/RegExr/
ajoutez les lignes suivantes, elles seront toutes mises en surbrillance si vous utilisez la première regex, sans le premier et le dernier / (ils sont à utiliser dans le code ruby).
2004-02-01
2004/02/01
01-02-2004
1-2-2004
2004-2-1
32-13-2010
qui sont incorrectes.
'00/00/0000'
et '99-99/9999'
sont des candidats possibles.
Il est plus facile de vérifier l'exactitude d'une date si vous spécifiez le format de date attendu. Cependant, même dans ce cas, Ruby est un peu trop tolérant pour mon cas d'utilisation:
Date.parse("Tue, 2017-01-17", "%a, %Y-%m-%d") # works
Date.parse("Wed, 2017-01-17", "%a, %Y-%m-%d") # works - !?
De toute évidence, au moins une de ces chaînes spécifie le mauvais jour de la semaine, mais Ruby ignore volontiers cela.
Voici une méthode qui ne le fait pas; il valide cette date.strftime(format)
conversion en la même chaîne d'entrée avec laquelle il a analysé Date.strptime
selon 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
est rempli de zéro. Si vous voulez quelque chose de différent, voir ruby-doc.org/stdlib-2.4.0/libdoc/date/rdoc/…
Publier ceci parce qu'il pourrait être utile à quelqu'un plus tard. Aucune idée si c'est une "bonne" façon de le faire ou non, mais cela fonctionne pour moi et est extensible.
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
Ce module complémentaire pour la classe String vous permet de spécifier votre liste de délimiteurs à la ligne 4, puis votre liste de formats valides à la ligne 5. Ce n'est pas sorcier, mais il est vraiment facile à étendre et vous permet simplement de vérifier une chaîne comme ceci:
"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
Vous pouvez essayer ce qui suit, ce qui est simple:
"31-02-2010".try(:to_date)
Mais vous devez gérer l'exception.
Date.parse n'a pas soulevé d'exception pour ces exemples:
Date.parse("12!12*2012")
=> Thu, 12 Apr 2018
Date.parse("12!12&2012")
=> Thu, 12 Apr 2018
Je préfère cette solution:
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
Méthode:
require 'date'
def is_date_valid?(d)
Date.valid_date? *"#{Date.strptime(d,"%m/%d/%Y")}".split('-').map(&:to_i) rescue nil
end
Usage:
config[:dates].split(",").all? { |x| is_date_valid?(x)}
Cela renvoie vrai ou faux si config [: dates] = "12/10 / 2012,05 / 09/1520"