कैसे जांचा जाए कि स्ट्रिंग एक वैध तिथि है


114

मेरे पास एक स्ट्रिंग है: "31-02-2010"और यह जांचना चाहते हैं कि यह वैध तारीख है या नहीं। यह करने के लिए सबसे अच्छा तरीका क्या है?

मुझे एक ऐसी विधि की आवश्यकता है, जो अगर स्ट्रिंग वैध तिथि है और यदि यह नहीं है तो यह सही है।


2
सिर्फ एक स्ट्रिंग में लेने के बजाय डेट_टाइम ड्रॉप डाउन क्यों न करें, जिसे आपको मान्य करना है?
जीर्णशीर्ण

ग्राहक की आवश्यकता। मैं पहले से ही यह सुझाव देता हूं, लेकिन ऐसा नहीं कर सकता :)
सलिल

एक सामान्य नियम के रूप में, क्या आपको किसी एप्लिकेशन के सामने के छोर पर इनपुट सत्यापन नहीं करना है?
सीनियनीज

यहाँ बहुत बेहतर जवाब - यह कैसे करना है। stackoverflow.com/questions/597328/…
n13

3
हमेशा बैकएंड पर मान्य करें, चाहे आपका फ्रंट-एंड कितना ही अच्छा क्यों न हो, इस पर भरोसा न करें!
स्पार्क

जवाबों:


112
require 'date'
begin
   Date.parse("31-02-2010")
rescue ArgumentError
   # handle invalid date
end

27
यह एक तारीख वर्ग की विशेषता नहीं है, यह अपवाद से निपटने है।
पियर-ओलिवियर थिबॉल्ट

3
Date.parse ('2012-08-13 == 00:00:00') # => सोम, 13 अगस्त 2012
बॉब

13
"कैच-इट-ऑल" बचाव का उपयोग करना एक विरोधी पैटर्न माना जाना चाहिए। यह उन अन्य त्रुटियों को छिपा सकता है, जिनकी हम अपेक्षा नहीं करते हैं और कोड की डीबगिंग को बहुत कठिन बना देते हैं।
यगौर

8
इसलिए ... अगर यह वास्तव में एक विरोधी पैटर्न है, तो आप इस सवाल का जवाब कैसे देंगे?
मैथ्यू ब्राउन

11
क्षमा करें यह एक गलत उत्तर है। यह जाँच नहीं करता है कि स्ट्रिंग एक वैध तिथि है या नहीं, यह केवल Date.parse की जाँच करता है, स्ट्रिंग को पार्स कर सकता है। Date.parse बहुत क्षमाशील प्रतीत होता है जब यह तारीखों की बात आती है, जैसे यह दिनांक 2012-09-09 के रूप में "FOOBAR_09_2010" को पार्स करेगा।
n13

54

यहाँ एक सरल एक लाइनर है:

DateTime.parse date rescue nil

मैं शायद वास्तविक जीवन में हर स्थिति में ऐसा करने की सिफारिश नहीं करूंगा क्योंकि आप कॉल करने वाले को शून्य की जांच करने के लिए मजबूर करते हैं, उदाहरण के लिए। खासकर जब स्वरूपण। यदि आप एक डिफ़ॉल्ट दिनांक लौटाते हैं। त्रुटि यह मित्रता हो सकती है।


8
DateTime.parse "123" बचाव निल। यह एक वास्तविक तारीख देता है .. मई 3 2017
baash05

3
Date.strptime(date, '%d/%m/%Y') rescue nil
बोनाफेरनोन्डो

1
इनलाइन rescueका उपयोग हतोत्साहित किया जाता है।
स्मॉयथ

52
d, m, y = date_string.split '-'
Date.valid_date? y.to_i, m.to_i, d.to_i

यह xx-xx-YYYY प्रारूप को लागू करने के लिए बहुत सरल और अच्छा है
n13

यदि आप एक सख्त एकल प्रारूप दिनांक स्ट्रिंग विकल्प को लागू करना चाहते हैं, तो यह सबसे अच्छा विकल्प है क्योंकि यह अपवाद से बचा जाता है और नियतात्मक है। Date.valid_date? रूबी के लिए कम से कम 2 का उपयोग करने की विधि है। ruby-doc.org/stdlib-2.0.0/libdoc/date/rdoc/…
Ashley Raiteri

4
रूबी किस संस्करण का समर्थन करती है is_valid?? 1.8, 2.0 और 2.1 की कोशिश की। उनमें से किसी को भी ऐसा नहीं लगता है। सभी को लगता है valid_date?, यद्यपि।
हेनरिक एन

29

पार्सिंग तिथियां कुछ गोचरों में चल सकती हैं, खासकर जब वे एमएम / डीडी / वाईवाईवाईवाई या डीडी / एमएम / वाईवाईवाईवाई प्रारूप में होते हैं, जैसे कि यूएस या यूरोप में उपयोग की जाने वाली छोटी तिथियां।

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)>

पहले अमेरिका के लिए सही प्रारूप था: मिमी / डीडी / yyyy, लेकिन दिनांक इसे पसंद नहीं था। दूसरा यूरोप के लिए सही था, लेकिन यदि आपके ग्राहक मुख्य रूप से यूएस-आधारित हैं, तो आपको बहुत खराब तारीखें मिलेंगी।

रूबी का Date.strptimeउपयोग इस तरह किया जाता है:

>> Date.strptime('12/31/2001', '%m/%d/%Y') #=> #<Date: 2001-12-31 (4904549/2,0,2299161)>

आपका LOCALE बंद लगता है। मुझे यह मिलता है >> Date.parse ('01 / 31/2001 ') => बुध, 31 जनवरी 2001 >>>? Date.parse ('31 / 01/2001') तर्क: अवैध तारीख
hoyhoy

यकीन नहीं हो रहा है कि मैं यहाँ बेवफा हूँ, लेकिन यह केवल एक तारीख को पार्स करने का तरीका बताता है, न कि इसे कैसे मान्य किया जाए। स्वीकृत उत्तर ArgumentError अपवाद का उपयोग करता है, लेकिन यह एक अच्छे विचार की तरह प्रतीत नहीं होता है, एक टिप्पणी में उल्लेखित कारणों के लिए।
cesoid

वहाँ एक ज्ञात स्थिति है जहाँ आप एक तारीख को मान्य नहीं कर सकते हैं। यह वह जगह है जहां दिन और महीने के मूल्य अस्पष्ट हैं, और आपको आने वाली तारीख स्ट्रिंग के प्रारूप को जानना होगा। और, यही उत्तर कह रहा है। यदि यह दिखता है 01/01/2014, तो कौन सा महीना है और कौन सा दिन है? अमेरिकी महीने में पहला होगा, बाकी दुनिया में यह दूसरा होगा।
टिन मैन

अस्पष्टता जो आपको तारीख को सत्यापित करने से रोकती है, केवल इस हद तक है कि यह आपको तारीख को पार्स करने से भी रोकती है, लेकिन आपने इसे ज्ञात जानकारी के साथ पार्स करने का एक अच्छा प्रयास किया है। आप में से कुछ का उपयोग करने के लिए अच्छा होगा कि आप जितना हो सके उतना अच्छा करने की कोशिश करें। क्या आप यह सोच सकते हैं कि Date.parse और Date.strptime अपवादों का उपयोग किए बिना ऐसा कैसे करें?
cesoid

दिनांक को "mm / dd / yyyy" या "dd / mm / yyyy" प्रारूप में पार्स करने की तिथि की प्रारूप की आवश्यकता का पूर्वाभास। इसके बिना हम यह निर्धारित नहीं कर सकते कि यह तब तक है जब तक कि हमारे पास एक स्रोत / उपयोगकर्ता से नमूना न हो, फिर दोनों रूपों का उपयोग करके पार्स करें और फिर देखें कि किस फॉर्म ने सबसे अधिक अपवाद उत्पन्न किए और दूसरे का उपयोग किया। कई स्रोतों से तारीखें पार्स करने पर यह टूट जाता है, खासकर जब वे वैश्विक होते हैं या वे हाथ से दर्ज किए गए होते हैं। तारीखों से निपटने का एकमात्र सटीक तरीका है हाथ से-प्रवेश की अनुमति न देना, उपयोगकर्ताओं को डेट-पिकर का उपयोग करने के लिए बाध्य करना, या केवल आईएसओ तिथि के प्रारूप की अनुमति देना जो असंदिग्ध हैं।
टीन मैन

26

Date.valid_date? *date_string.split('-').reverse.map(&:to_i)


उत्कृष्ट धन्यवाद। यह कम से कम 1.8, 2.0 और 2.1 में उपलब्ध लगता है। ध्यान दें कि आपको require "date"पहले या "अपरिभाषित विधि" प्राप्त करनी होगी।
हेनरिक एन

2
यह विधि गलत वापस करने के बजाय एक अपवाद 'तर्क-वितर्क: गलत संख्या में तर्क' जुटा सकती है। उदाहरण के लिए यदि आपके स्ट्रिंग में डैश के बजाय स्लैश हैं
vincentp

2
हो सकता है कि हम खराब फॉर्मेट की तारीख से निपटने के लिए ऐसा कुछ कर सकते हैं:Date.valid_date? *Array.new(3).zip(date_string.split('-')).transpose.last.reverse.map(&:to_i)
vincentp

9

मैं 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'

5

दिनांक मान्य करने का दूसरा तरीका:

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)

3

सभी तिथियों के लिए 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/

निम्नलिखित पंक्तियों को जोड़ दें, वे सभी हाइलाइट होंगे यदि आप पहली रेगेक्स का उपयोग करते हैं, बिना पहले और अंतिम / (वे माणिक कोड में उपयोग के लिए हैं)।

2004-02-01
2004/02/01
01-02-2004
1-2-2004
2004-2-1

2
यह नियमित अभिव्यक्ति केवल कुछ निश्चित स्वरूपों से मेल खाती है, बिना किसी तिथि के शब्दार्थ के बारे में परवाह किए बिना। आपका मिलान तारीखों को अनुमति देता है जैसे कि 32-13-2010गलत है।
यगौर

2
यदि आप एक मोटा अनुमान चाहते हैं तो बहुत अच्छा है अगर किसी भी मनमाने तार को तारीख के रूप में पार्स किया जा सकता है।
नील गुडमैन

जहां "किसी न किसी अनुमान" का अर्थ है जैसे कि '00/00/0000'और '99-99/9999'संभावित उम्मीदवार हैं।
टीन मैन

1
जब कस्टम regex एक बुरा विचार है का एक शानदार उदाहरण!
टॉम लॉर्ड

3

एक कठोर समाधान

यदि आप अपेक्षित तारीख प्रारूप को निर्दिष्ट करते हैं, तो किसी तिथि की शुद्धता को सत्यापित करना आसान है। हालांकि, तब भी, रूबी मेरे उपयोग के मामले के लिए थोड़ा सहनशील है:

Date.parse("Tue, 2017-01-17", "%a, %Y-%m-%d") # works
Date.parse("Wed, 2017-01-17", "%a, %Y-%m-%d") # works - !?

स्पष्ट रूप से, इनमें से कम से कम एक तार गलत कार्यदिवस को निर्दिष्ट करता है, लेकिन रूबी खुशी से नजरअंदाज कर देती है।

यहाँ एक विधि है जो नहीं करता है; यह पुष्टि 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

ठीक वैसा ही मैं देख रहा था। धन्यवाद!
लुकास केटन

यह "2019-1-1" जैसे मामलों के लिए विफल है, जो एक वैध तारीख है, लेकिन अकड़ इसे 2019-01-01 बनाता है
saGii

@saGii जो निर्दिष्ट प्रारूप को फिट नहीं करता है (iso8601 - देखें Date.today().iso8601); %mशून्य-गद्देदार है। यदि आप कुछ अलग चाहते हैं, तो ruby-doc.org/stdlib-2.4.0/libdoc/date/rdoc/…
नाथन लॉन्ग

2

इसे पोस्ट करना क्योंकि यह बाद में किसी के लिए उपयोग हो सकता है। कोई सुराग नहीं अगर यह करने के लिए एक "अच्छा" तरीका है या नहीं, लेकिन यह मेरे लिए काम करता है और विस्तार योग्य है।

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

स्ट्रिंग क्लास के लिए यह ऐड-ऑन आपको लाइन 4 में डेलिमेटर्स की अपनी सूची और फिर लाइन 5 में मान्य प्रारूपों की आपकी सूची को निर्दिष्ट करने देता है। रॉकेट साइंस नहीं, लेकिन यह वास्तव में विस्तार करना आसान बनाता है और आपको बस एक स्ट्रिंग की जांच करने देता है:

"test".is_date?
"10-12-2010".is_date?
params[:some_field].is_date?
etc.

0
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

0

आप निम्नलिखित कोशिश कर सकते हैं, जो सरल तरीका है:

"31-02-2010".try(:to_date)

लेकिन आपको अपवाद को संभालने की आवश्यकता है।


0

दिनांक.इस उदाहरण के लिए अपवाद नहीं उठाया गया:

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

-1

तरीका:

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)}

यह सच है या गलत है अगर विन्यास [: दिनांक] = "12/10 / 2012,05 / 09/1520"

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.