ฉันมีสตริง: "31-02-2010"
และต้องการตรวจสอบว่าเป็นวันที่ที่ถูกต้องหรือไม่ วิธีที่ดีที่สุดคืออะไร?
ฉันต้องการเมธอดที่คืนค่าจริงหากสตริงเป็นวันที่ที่ถูกต้องและเป็นเท็จหากไม่ใช่
ฉันมีสตริง: "31-02-2010"
และต้องการตรวจสอบว่าเป็นวันที่ที่ถูกต้องหรือไม่ วิธีที่ดีที่สุดคืออะไร?
ฉันต้องการเมธอดที่คืนค่าจริงหากสตริงเป็นวันที่ที่ถูกต้องและเป็นเท็จหากไม่ใช่
คำตอบ:
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?
แต่
การแยกวิเคราะห์วันที่สามารถใช้งานได้ใน gotcha โดยเฉพาะอย่างยิ่งเมื่ออยู่ในรูปแบบ MM / DD / YYYY หรือ DD / MM / YYYY เช่นวันที่สั้น ๆ ที่ใช้ในสหรัฐอเมริกาหรือยุโรป
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)>
รูปแบบแรกคือรูปแบบที่ถูกต้องสำหรับสหรัฐอเมริกา: mm / dd / yyyy แต่ Date ไม่ชอบ ประการที่สองถูกต้องสำหรับยุโรป แต่ถ้าลูกค้าของคุณส่วนใหญ่อยู่ในสหรัฐอเมริกาคุณจะได้รับวันที่ที่แยกวิเคราะห์ไม่ดีจำนวนมาก
ทับทิม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)
ลอง regex สำหรับวันที่ทั้งหมด:
/(\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/
เพิ่มบรรทัดต่อไปนี้ซึ่งทั้งหมดจะถูกไฮไลต์หากคุณใช้ regex แรกโดยไม่ต้องใช้ / บรรทัดแรกและตัวสุดท้าย (ใช้สำหรับรหัสทับทิม)
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
Add-on สำหรับคลาส 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 [: วันที่] = "12/10 / 2012,05 / 09/1520"