У меня есть строка: "31-02-2010"
и я хочу проверить, действительна ли это дата. Как лучше всего это сделать?
Мне нужен метод, который возвращает true, если строка является действительной датой, и false, если это не так.
У меня есть строка: "31-02-2010"
и я хочу проверить, действительна ли это дата. Как лучше всего это сделать?
Мне нужен метод, который возвращает true, если строка является действительной датой, и false, если это не так.
Ответы:
require 'date'
begin
Date.parse("31-02-2010")
rescue ArgumentError
# handle invalid date
end
Вот простой лайнер:
DateTime.parse date rescue nil
Я бы, вероятно, не рекомендовал делать именно это в каждой ситуации в реальной жизни, поскольку вы заставляете вызывающего абонента проверять ноль, например. особенно при форматировании. Если вы вернете дату по умолчанию | ошибка, это может быть удобнее.
Date.strptime(date, '%d/%m/%Y') rescue nil
rescue
не рекомендуется.
d, m, y = date_string.split '-'
Date.valid_date? y.to_i, m.to_i, d.to_i
is_valid?
? Пробовал 1.8, 2.0 и 2.1. Похоже, ни у кого из них этого нет. valid_date?
Хотя, похоже , все имеют .
При анализе дат могут возникать некоторые проблемы, особенно когда они указаны в формате ММ / ДД / ГГГГ или ДД / ММ / ГГГГ, например, короткие даты, используемые в США или Европе.
Date#parse
пытается выяснить, какой из них использовать, но в течение года бывает много дней в месяце, когда неоднозначность между форматами может вызвать проблемы синтаксического анализа.
Я бы порекомендовал выяснить, что такое LOCALE пользователя, а затем, основываясь на этом, вы будете знать, как разумно анализировать, используя Date.strptime
. Лучший способ узнать, где находится пользователь, - спросить его во время регистрации, а затем указать параметр в его предпочтениях, чтобы изменить его. Предполагая, что вы можете откопать это с помощью какой-то умной эвристики и не беспокоить пользователя этой информацией, это может привести к неудаче, поэтому просто спросите.
Это тест с использованием Date.parse
. Я в США:
>> Date.parse('01/31/2001')
ArgumentError: invalid date
>> Date.parse('31/01/2001') #=> #<Date: 2001-01-31 (4903881/2,0,2299161)>
Первым был правильный формат для США: мм / дд / гггг, но Дате он не понравился. Второе было правильным для Европы, но если ваши клиенты преимущественно проживают в США, вы получите много плохо разобранных дат.
Ruby Date.strptime
используется как:
>> Date.strptime('12/31/2001', '%m/%d/%Y') #=> #<Date: 2001-12-31 (4904549/2,0,2299161)>
01/01/2014
, какой месяц, а какой день? В США месяц будет первым, в остальном мире - вторым.
Date.valid_date? *date_string.split('-').reverse.map(&:to_i)
require "date"
сначала, иначе вы получите «неопределенный метод».
Date.valid_date? *Array.new(3).zip(date_string.split('-')).transpose.last.reverse.map(&:to_i)
Я хочу продлить Date
класс.
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'
Другой способ проверить дату:
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)
Попробуйте регулярное выражение для всех дат:
/(\d{1,2}[-\/]\d{1,2}[-\/]\d{4})|(\d{4}[-\/]\d{1,2}[-\/]\d{1,2})/.match("31-02-2010")
Только для вашего формата с ведущими нулями, последним годом и дефисами:
/(\d{2}-\d{2}-\d{4})/.match("31-02-2010")
[- /] означает или - или /, косая черта должна быть экранирована. Вы можете проверить это на http://gskinner.com/RegExr/
добавьте следующие строки, все они будут выделены, если вы используете первое регулярное выражение, без первого и последнего / (они используются в коде ruby).
2004-02-01
2004/02/01
01-02-2004
1-2-2004
2004-2-1
32-13-2010
который неверен".
'00/00/0000'
и '99-99/9999'
являются возможными кандидатами.
Проверить правильность даты проще, если указать ожидаемый формат даты. Однако даже в этом случае Ruby слишком терпим для моего варианта использования:
Date.parse("Tue, 2017-01-17", "%a, %Y-%m-%d") # works
Date.parse("Wed, 2017-01-17", "%a, %Y-%m-%d") # works - !?
Ясно, что по крайней мере одна из этих строк указывает неправильный день недели, но Ruby с радостью игнорирует это.
Вот метод, который этого не делает; это подтверждает , что date.strftime(format)
обращенные назад к одной и той же входной строке , что она разобранной с Date.strptime
согласно 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
дополняется нулями. Если вы хотите чего-то другого, см. Ruby-doc.org/stdlib-2.4.0/libdoc/date/rdoc/…
Публикуем это, потому что это может быть кому-то полезно позже. Не знаю, «хороший» это способ сделать это или нет, но он работает для меня и его можно расширить.
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
Это дополнение для класса String позволяет указать список разделителей в строке 4, а затем список допустимых форматов в строке 5. Это не ракетостроение, но упрощает его расширение и позволяет просто проверять строку следующим образом:
"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
Вы можете попробовать следующий простой способ:
"31-02-2010".try(:to_date)
Но вам нужно обработать исключение.
Date.parse не вызывает исключения для этих примеров:
Date.parse("12!12*2012")
=> Thu, 12 Apr 2018
Date.parse("12!12&2012")
=> Thu, 12 Apr 2018
Я предпочитаю это решение:
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'
def is_date_valid?(d)
Date.valid_date? *"#{Date.strptime(d,"%m/%d/%Y")}".split('-').map(&:to_i) rescue nil
end
Использование:
config[:dates].split(",").all? { |x| is_date_valid?(x)}
Это возвращает истину или ложь, если config [: date] = "12.10.2012, 05.09.1520"