Eu tenho uma string: "31-02-2010"
e quero verificar se é ou não uma data válida. Qual é a melhor maneira de fazer isso?
Preciso de um método que retorne verdadeiro se a string for uma data válida e falso se não for.
Eu tenho uma string: "31-02-2010"
e quero verificar se é ou não uma data válida. Qual é a melhor maneira de fazer isso?
Preciso de um método que retorne verdadeiro se a string for uma data válida e falso se não for.
Respostas:
require 'date'
begin
Date.parse("31-02-2010")
rescue ArgumentError
# handle invalid date
end
Aqui está um liner simples:
DateTime.parse date rescue nil
Eu provavelmente não recomendaria fazer exatamente isso em todas as situações da vida real, ao forçar o chamador a verificar se há zero, por exemplo. particularmente durante a formatação. Se você retornar um erro de data | padrão, pode ser mais amigável.
Date.strptime(date, '%d/%m/%Y') rescue nil
rescue
é recomendado.
d, m, y = date_string.split '-'
Date.valid_date? y.to_i, m.to_i, d.to_i
is_valid?
? Tentei 1.8, 2.0 e 2.1. Nenhum deles parece ter esse. Todos parecem ter valid_date?
, no entanto.
As datas de análise podem ser complicadas, especialmente quando estão no formato MM / DD / AAAA ou DD / MM / AAAA, como datas curtas usadas nos EUA ou na Europa.
Date#parse
tenta descobrir qual usar, mas há muitos dias em um mês ao longo do ano em que a ambiguidade entre os formatos pode causar problemas de análise.
Eu recomendo descobrir qual é a LOCALE do usuário, então, com base nisso, você saberá como analisar de forma inteligente usando Date.strptime
. A melhor maneira de descobrir onde um usuário está localizado é perguntar a ele durante a inscrição e, em seguida, fornecer uma configuração em suas preferências para alterá-la. Supondo que você possa desenterrá-lo por meio de alguma heurística inteligente e não incomodar o usuário com essa informação, está sujeito a falhas, então é só perguntar.
Este é um teste usando Date.parse
. Estou nos EUA:
>> Date.parse('01/31/2001')
ArgumentError: invalid date
>> Date.parse('31/01/2001') #=> #<Date: 2001-01-31 (4903881/2,0,2299161)>
O primeiro era o formato correto para os EUA: mm / dd / aaaa, mas Date não gostou. A segunda estava correta para a Europa, mas se seus clientes residirem predominantemente nos EUA, você obterá muitas datas mal analisadas.
Ruby Date.strptime
é usado como:
>> Date.strptime('12/31/2001', '%m/%d/%Y') #=> #<Date: 2001-12-31 (4904549/2,0,2299161)>
01/01/2014
, qual é o mês e qual é o dia? No mês dos EUA seria o primeiro, no resto do mundo seria o segundo.
Date.valid_date? *date_string.split('-').reverse.map(&:to_i)
require "date"
primeiro ou obterá "método indefinido".
Date.valid_date? *Array.new(3).zip(date_string.split('-')).transpose.last.reverse.map(&:to_i)
Eu gostaria de estender a Date
aula.
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'
Outra forma de validar a 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)
Experimente regex para todas as datas:
/(\d{1,2}[-\/]\d{1,2}[-\/]\d{4})|(\d{4}[-\/]\d{1,2}[-\/]\d{1,2})/.match("31-02-2010")
Apenas para o seu formato com zeros à esquerda, último ano e travessões:
/(\d{2}-\d{2}-\d{4})/.match("31-02-2010")
o [- /] significa - ou /, a barra deve ter escape. Você pode testar isso em http://gskinner.com/RegExr/
adicione as seguintes linhas, todas elas serão destacadas se você usar a primeira regex, sem a primeira e a última / (elas são para uso em código ruby).
2004-02-01
2004/02/01
01-02-2004
1-2-2004
2004-2-1
32-13-2010
erradas.
'00/00/0000'
e '99-99/9999'
são possíveis candidatos.
É mais fácil verificar se uma data está correta se você especificar o formato de data esperado. No entanto, mesmo assim, Ruby é um pouco tolerante demais para o meu caso de uso:
Date.parse("Tue, 2017-01-17", "%a, %Y-%m-%d") # works
Date.parse("Wed, 2017-01-17", "%a, %Y-%m-%d") # works - !?
Claramente, pelo menos uma dessas strings especifica o dia da semana errado, mas Ruby felizmente ignora isso.
Aqui está um método que não funciona; ele valida que date.strftime(format)
convertidos de volta à mesma cadeia de entrada que ele seja analisado com Date.strptime
segundo 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
é preenchido com zeros. Se você quiser algo diferente, consulte ruby-doc.org/stdlib-2.4.0/libdoc/date/rdoc/…
Postar isso porque pode ser útil para alguém mais tarde. Não tenho ideia se essa é uma "boa" maneira de fazer isso ou não, mas funciona para mim e é extensível.
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
Este complemento para a classe String permite que você especifique sua lista de delimitadores na linha 4 e, em seguida, sua lista de formatos válidos na linha 5. Não é nada complicado, mas torna muito fácil estender e permite que você simplesmente verifique uma string como:
"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
Você pode tentar o seguinte, que é a maneira mais simples:
"31-02-2010".try(:to_date)
Mas você precisa lidar com a exceção.
Date.parse não gerou exceção para estes exemplos:
Date.parse("12!12*2012")
=> Thu, 12 Apr 2018
Date.parse("12!12&2012")
=> Thu, 12 Apr 2018
Eu prefiro esta solução:
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étodo:
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)}
Isso retorna verdadeiro ou falso se config [: datas] = "10/12/2012, 05/09/1520"