ruby-on-rails - rails - ruby time format
Cómo verificar si una cadena es una fecha válida (14)
Tengo una cadena: "31-02-2010"
y quiero verificar si es o no una fecha válida. ¿Cuál es la mejor manera de hacerlo?
Necesito un método que devuelva verdadero si la cadena es una fecha válida y falso si no lo es.
Una solución más estricta
Es más fácil verificar la exactitud de una fecha si especifica el formato de fecha que espera. Sin embargo, incluso entonces, Ruby es un poco tolerante con mi 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, al menos una de estas cadenas especifica el día de la semana equivocado, pero Ruby felizmente ignora eso.
Aquí hay un método que no; valida que date.strftime(format)
convierta de nuevo a la misma cadena de entrada que analizó con Date.strptime
según el 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
Aquí hay un trazador de líneas simple:
DateTime.parse date rescue nil
Probablemente no recomendaría hacer exactamente esto en cada situación en la vida real, ya que obligaría a la persona que llama a verificar nulo, por ejemplo. particularmente al formatear. Si devuelve un error de fecha predeterminado, puede ser más amigable.
Date.parse no planteado excepción para este ejemplo:
Date.parse("12!12*2012")
=> Thu, 12 Apr 2018
Date.parse("12!12&2012")
=> Thu, 12 Apr 2018
Yo prefiero esta solución:
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
Las fechas de análisis se pueden ejecutar en algunos programas, especialmente cuando están en formato MM / DD / AAAA o DD / MM / AAAA, como fechas cortas utilizadas en EE. UU. O Europa.
Date#parse
intenta averiguar qué usar, pero hay muchos días en un mes a lo largo del año en que la ambigüedad entre los formatos puede causar problemas de análisis.
Recomiendo descubrir cuál es el LOCALE del usuario, luego, en base a eso, sabrá cómo analizar inteligentemente usando Date.strptime
. La mejor forma de encontrar dónde se encuentra un usuario es preguntárselo durante el registro y luego proporcionar una configuración en sus preferencias para cambiarlo. Asumiendo que puede desenterrarlo mediante alguna heurística inteligente y no molestar al usuario por esa información, es propenso a fallar así que solo pregunte.
Esta es una prueba usando Date.parse
. Estoy en los Estados Unidos:
>> Date.parse(''01/31/2001'')
ArgumentError: invalid date
>> Date.parse(''31/01/2001'') #=> #<Date: 2001-01-31 (4903881/2,0,2299161)>
El primero fue el formato correcto para los EE. UU .: mm / dd / aaaa, pero a Date no le gustó. El segundo era correcto para Europa, pero si sus clientes son predominantemente estadounidenses, obtendrá muchas fechas mal analizadas.
Ruby''s Date.strptime
se usa como:
>> Date.strptime(''12/31/2001'', ''%m/%d/%Y'') #=> #<Date: 2001-12-31 (4904549/2,0,2299161)>
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)}
Esto devuelve verdadero o falso si config [: fechas] = "12/10 / 2012,05 / 09/1520"
Me gustaría extender la clase de Date
.
class Date
def self.parsable?(string)
begin
parse(string)
true
rescue ArgumentError
false
end
end
end
ejemplo
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''
Otra forma de validar la fecha:
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)
Prueba regex para todas las fechas:
/(/d{1,2}[-//]/d{1,2}[-//]/d{4})|(/d{4}[-//]/d{1,2}[-//]/d{1,2})/.match("31-02-2010")
Solo para su formato con ceros a la izquierda, año último y guiones:
/(/d{2}-/d{2}-/d{4})/.match("31-02-2010")
[- /] significa - o /, la barra diagonal debe ser escapada. Puedes probar esto en http://gskinner.com/RegExr/
agregue las siguientes líneas, se resaltarán todas si usa la primera expresión regular, sin la primera y última / (son para usar en el código Ruby).
2004-02-01
2004/02/01
01-02-2004
1-2-2004
2004-2-1
Publicar esto porque podría ser útil para alguien más tarde. No tengo idea si esta es una "buena" manera de hacerlo o no, pero funciona para mí y es 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
Este add-on para la clase String te permite especificar tu lista de delimitadores en la línea 4 y luego tu lista de formatos válidos en la línea 5. No es ciencia ficción, pero hace que sea muy fácil de extender y te permite simplemente verificar una cadena como esta:
"test".is_date?
"10-12-2010".is_date?
params[:some_field].is_date?
etc.
Puede intentar lo siguiente, que es la manera más simple:
"31-02-2010".try(:to_date)
Pero debes manejar la excepción.
Date.valid_date? *date_string.split(''-'').reverse.map(&:to_i)
d, m, y = date_string.split ''-''
Date.valid_date? y.to_i, m.to_i, d.to_i
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
require ''date''
begin
Date.parse("31-02-2010")
rescue ArgumentError
# handle invalid date
end