Tôi có một chuỗi: "31-02-2010"
và muốn kiểm tra xem đó có phải là ngày hợp lệ hay không. Cách tốt nhất để làm điều đó là gì?
Tôi cần một phương thức trả về true nếu chuỗi là ngày hợp lệ và false nếu không phải.
Tôi có một chuỗi: "31-02-2010"
và muốn kiểm tra xem đó có phải là ngày hợp lệ hay không. Cách tốt nhất để làm điều đó là gì?
Tôi cần một phương thức trả về true nếu chuỗi là ngày hợp lệ và false nếu không phải.
Câu trả lời:
require 'date'
begin
Date.parse("31-02-2010")
rescue ArgumentError
# handle invalid date
end
Đây là một lớp lót đơn giản:
DateTime.parse date rescue nil
Tôi có lẽ không khuyên bạn nên làm điều này chính xác trong mọi tình huống trong cuộc sống thực vì bạn buộc người gọi kiểm tra nil, ví dụ: đặc biệt là khi định dạng. Nếu bạn trả về lỗi ngày | mặc định thì nó có thể thân thiện hơn.
Date.strptime(date, '%d/%m/%Y') rescue nil
rescue
khuyến khích sử dụng nội tuyến .
d, m, y = date_string.split '-'
Date.valid_date? y.to_i, m.to_i, d.to_i
is_valid?
? Đã thử 1.8, 2.0 và 2.1. Không ai trong số họ dường như có cái đó. Tất cả dường như có valid_date?
, mặc dù.
Phân tích cú pháp ngày có thể gặp phải một số gotcha, đặc biệt khi chúng ở định dạng MM / DD / YYYY hoặc DD / MM / YYYY, chẳng hạn như các ngày ngắn được sử dụng ở Hoa Kỳ hoặc Châu Âu.
Date#parse
cố gắng tìm ra cái nào để sử dụng, nhưng có nhiều ngày trong một tháng trong năm khi sự không rõ ràng giữa các định dạng có thể gây ra sự cố phân tích cú pháp.
Tôi khuyên bạn nên tìm hiểu LOCALE của người dùng là gì, sau đó, dựa vào đó, bạn sẽ biết cách phân tích cú pháp thông minh bằng cách sử dụng Date.strptime
. Cách tốt nhất để tìm vị trí của người dùng là hỏi họ trong quá trình đăng ký, sau đó cung cấp cài đặt theo sở thích của họ để thay đổi cài đặt đó. Giả sử bạn có thể khai thác nó bằng một số kinh nghiệm thông minh và không làm phiền người dùng về thông tin đó, thì rất dễ bị thất bại, vì vậy hãy hỏi.
Đây là một thử nghiệm sử dụng Date.parse
. Tôi đang ở Mỹ:
>> Date.parse('01/31/2001')
ArgumentError: invalid date
>> Date.parse('31/01/2001') #=> #<Date: 2001-01-31 (4903881/2,0,2299161)>
Đầu tiên là định dạng chính xác cho Hoa Kỳ: mm / dd / yyyy, nhưng Date không thích nó. Điều thứ hai đúng đối với Châu Âu, nhưng nếu khách hàng của bạn chủ yếu sống ở Hoa Kỳ, bạn sẽ nhận được rất nhiều ngày được phân tích cú pháp sai.
Ruby Date.strptime
được sử dụng như:
>> Date.strptime('12/31/2001', '%m/%d/%Y') #=> #<Date: 2001-12-31 (4904549/2,0,2299161)>
01/01/2014
, đó là tháng và ngày nào? Ở Mỹ, tháng sẽ đứng đầu, các nước còn lại trên thế giới sẽ đứng thứ hai.
Date.valid_date? *date_string.split('-').reverse.map(&:to_i)
require "date"
trước nếu không bạn sẽ nhận được "phương thức không xác định".
Date.valid_date? *Array.new(3).zip(date_string.split('-')).transpose.last.reverse.map(&:to_i)
Tôi muốn mở rộng Date
lớp học.
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'
Một cách khác để xác thực ngày:
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)
Hãy thử regex cho tất cả các ngày:
/(\d{1,2}[-\/]\d{1,2}[-\/]\d{4})|(\d{4}[-\/]\d{1,2}[-\/]\d{1,2})/.match("31-02-2010")
Chỉ dành cho định dạng của bạn với các số 0 ở đầu, năm trước và dấu gạch ngang:
/(\d{2}-\d{2}-\d{4})/.match("31-02-2010")
[- /] có nghĩa là - hoặc /, dấu gạch chéo phía trước phải được thoát ra. Bạn có thể kiểm tra điều này trên http://gskinner.com/RegExr/
thêm các dòng sau, tất cả chúng sẽ được đánh dấu nếu bạn sử dụng regex đầu tiên, không có đầu tiên và cuối cùng / (chúng được sử dụng trong mã ruby).
2004-02-01
2004/02/01
01-02-2004
1-2-2004
2004-2-1
32-13-2010
sai.
'00/00/0000'
và '99-99/9999'
có thể là các ứng cử viên.
Sẽ dễ dàng hơn để xác minh tính đúng đắn của một ngày nếu bạn chỉ định định dạng ngày mà bạn mong đợi. Tuy nhiên, ngay cả khi đó, Ruby vẫn hơi quá dung tục đối với trường hợp sử dụng của tôi:
Date.parse("Tue, 2017-01-17", "%a, %Y-%m-%d") # works
Date.parse("Wed, 2017-01-17", "%a, %Y-%m-%d") # works - !?
Rõ ràng, ít nhất một trong những chuỗi này chỉ định sai ngày trong tuần, nhưng Ruby vui vẻ bỏ qua điều đó.
Đây là một phương pháp không; nó xác thực sẽ date.strftime(format)
chuyển đổi trở lại cùng một chuỗi đầu vào mà nó đã phân tích cú pháp Date.strptime
theo đó 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
không có đệm. Nếu bạn muốn điều gì đó khác biệt, hãy xem ruby-doc.org/stdlib-2.4.0/libdoc/date/rdoc/…
Đăng cái này vì nó có thể được sử dụng cho ai đó sau này. Không có manh mối nào nếu đây là một cách "tốt" để làm điều đó hay không, nhưng nó hiệu quả với tôi và có thể mở rộng.
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
Tiện ích bổ sung này cho lớp String cho phép bạn chỉ định danh sách các dấu phân cách ở dòng 4 và sau đó là danh sách các định dạng hợp lệ của bạn ở dòng 5. Không phải là khoa học tên lửa, nhưng làm cho nó thực sự dễ dàng mở rộng và cho phép bạn chỉ cần kiểm tra một chuỗi như vậy:
"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
Bạn có thể thử cách sau, đó là cách đơn giản:
"31-02-2010".try(:to_date)
Nhưng bạn cần phải xử lý ngoại lệ.
Date.parse không nêu ra ngoại lệ cho các ví dụ này:
Date.parse("12!12*2012")
=> Thu, 12 Apr 2018
Date.parse("12!12&2012")
=> Thu, 12 Apr 2018
Tôi thích giải pháp này hơ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
Phương pháp:
require 'date'
def is_date_valid?(d)
Date.valid_date? *"#{Date.strptime(d,"%m/%d/%Y")}".split('-').map(&:to_i) rescue nil
end
Sử dụng:
config[:dates].split(",").all? { |x| is_date_valid?(x)}
Điều này trả về true hoặc false nếu config [: date] = "12/10 / 2012,05 / 09/1520"