문자열이 유효한 날짜인지 확인하는 방법


114

문자열 "31-02-2010"이 있으며 유효한 날짜인지 확인하고 싶습니다. 이를 수행하는 가장 좋은 방법은 무엇입니까?

문자열이 유효한 날짜이면 true를 반환하고 그렇지 않으면 false를 반환하는 메서드가 필요합니다.


2
유효성을 검사해야하는 문자열을 사용하는 대신 date_time 드롭 다운을 만드는 것이 어떻습니까?
— 부식

클라이언트의 요구 사항. 나는 이미 그것을 제안하지만 그렇게 할 수 없습니다 :)
— Salil

일반적으로 응용 프로그램의 프런트 엔드에서 입력 유효성 검사를 수행해야하지 않습니까?
— Seanny123

여기에 훨씬 더 나은 답변이 있습니다. 이것이 방법입니다. stackoverflow.com/questions/597328/…
— n13 '1311.04.12

3
프런트 엔드가 아무리 좋더라도 항상 백엔드에서 유효성을 검사하십시오. 신뢰하지 마십시오!
— SparK

답변:


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

27
Date 클래스 기능이 아니라 예외 처리입니다.
— Pier-Olivier Thibault

3
Date.parse ( '2012-08-13 == 00:00:00') # => 2012 년 8 월 13 일 월요일
— Bob

13
"범용"구조를 사용하는 것은 반 패턴으로 간주되어야합니다. 우리가 예상하지 못한 다른 오류를 숨기고 코드 디버깅을 매우 어렵게 만들 수 있습니다.
— yagooar

8
그래서 ... 정말로 안티 패턴이라면 질문에 어떻게 대답 하시겠습니까?
— Matthew Brown

11
죄송합니다. 잘못된 답변입니다. 문자열이 유효한 날짜인지 여부는 확인하지 않고 Date.parse 만 확인하여 문자열을 구문 분석 할 수 있습니다. Date.parse는 날짜와 관련하여 매우 관대 해 보입니다. 예를 들어 "FOOBAR_09_2010"을 2012-09-09 날짜로 구문 분석합니다.
— n13

54

다음은 간단한 라이너입니다.

DateTime.parse date rescue nil

예를 들어 호출자가 nil을 확인하도록 강제하기 때문에 실제 생활의 모든 상황에서 정확하게 이것을 수행하는 것은 권장하지 않습니다. 특히 포맷 할 때. 기본 날짜 | 오류를 반환하면 더 친숙 할 수 있습니다.


8
DateTime.parse "123"구조 nil. 실제 날짜를 반환합니다. 2017 년 5 월 3 일
— baash05

3
Date.strptime(date, '%d/%m/%Y') rescue nil
— bonafernando

1
인라인 사용 rescue은 권장되지 않습니다.
— smoyth

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/...은
— 애슐리 Raiteri

4
어떤 버전의 Ruby가 지원 is_valid?합니까? 1.8, 2.0 및 2.1을 시도했습니다. 그들 중 누구도 그것을 가지고 있지 않은 것 같습니다. valid_date?그래도 모두 가지고있는 것 같습니다 .
— Henrik N

29

파싱 ​​날짜는 특히 미국 또는 유럽에서 사용되는 짧은 날짜와 같이 MM / DD / YYYY 또는 DD / MM / YYYY 형식 인 경우 일부 문제가 발생할 수 있습니다.

Date#parse 어떤 것을 사용할지 알아 내려고하지만, 형식 간의 모호함으로 인해 구문 분석 문제가 발생할 수있는 1 년 내내 한 달에 여러 날이 있습니다.

사용자의 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는 마음에 들지 않았습니다. 두 번째는 유럽에 맞았지만 고객이 주로 미국에 기반을 둔 경우 잘못 구문 분석 된 날짜가 많이 표시됩니다.

Ruby Date.strptime는 다음과 같이 사용됩니다.

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

LOCALE이 꺼져있는 것 같습니다. 나는 이것을 얻는다 >> Date.parse ('01 / 31 / 2001 ') => Wed, 31 Jan 2001 >>?> Date.parse ('31 / 01 / 2001') ArgumentError : invalid date
— hoyhoy

내가 여기서 멍청한 지 확실하지 않지만 이것은 날짜를 확인하는 방법이 아니라 파싱하는 방법만을 설명하는 것 같습니다. 받아 들여지는 대답은 ArgumentError 예외를 사용하지만 주석에 언급 된 이유로 좋은 생각이 아닙니다.
— cesoid 2014

날짜를 확인할 수없는 알려진 상황이 있습니다. 일과 월 값이 모호한 곳이며 들어오는 날짜 문자열의 형식을 알아야합니다. 그리고 그것이 대답이 말하는 것입니다. 과 같이 보이면 01/01/2014월과 날짜는 무엇입니까? 미국에서는 1 월이 될 것이고, 나머지 세계에서는 2 번째가 될 것입니다.
— The Tin Man

날짜의 유효성을 검사하지 못하게하는 모호성은 날짜를 구문 분석하지 못하게하는 정도까지만 수행하지만 알려진 정보로 구문 분석을 시도했습니다. 우리가 할 수있는 한 최선을 다해 검증하기 위해 노력해야하는 것을 사용하는 것이 좋습니다. Date.parse 및 Date.strptime이 생성하는 예외를 사용하지 않고이를 수행하는 방법을 생각할 수 있습니까?
— cesoid 2015-08-14

"mm / dd / yyyy"또는 "dd / mm / yyyy"형식의 날짜 구문 분석에는 날짜 형식에 대한 사전 지식이 필요 합니다. 그것 없이는 우리가 하나의 소스 / 사용자로부터 샘플링을하지 않는 한 그것이 무엇인지 결정할 수 없습니다. 그런 다음 두 양식을 사용하여 구문 분석 한 다음 어떤 양식이 가장 많은 예외를 생성했는지 확인하고 다른 양식을 사용합니다. 이는 여러 소스의 날짜를 구문 분석 할 때, 특히 글로벌이거나 직접 입력 한 경우에 분석됩니다. 날짜를 정확하게 처리하는 유일한 방법은 직접 입력을 허용하지 않거나 사용자가 날짜 선택기를 사용하도록하거나 모호하지 않은 ISO 날짜 형식 만 허용하는 것입니다.
— The Tin Man

26

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


훌륭 해요, 고마워요. 이것은 적어도 1.8, 2.0 및 2.1에서 사용 가능한 것으로 보입니다. require "date"먼저 해야합니다. 그렇지 않으면 "정의되지 않은 메서드"가 표시됩니다.
— Henrik N

2
이 메서드는 false를 반환하는 대신 'ArgumentError : wrong number of arguments'예외를 발생시킬 수 있습니다. 예를 들어 문자열에 대시 대신 슬래시가 포함 된 경우
— 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

모든 날짜에 정규식을 사용해보십시오.

/(\d{1,2}[-\/]\d{1,2}[-\/]\d{4})|(\d{4}[-\/]\d{1,2}[-\/]\d{1,2})/.match("31-02-2010")

선행 0, 연도 및 대시가있는 형식의 경우 :

/(\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는 잘못된 날짜를 허용 합니다.
— yagooar

2
임의의 문자열을 날짜로 구문 분석 할 수 있는지 대략적인 추정치를 원하면 충분합니다.
— Neil Goodman

"대략적인 추정" 은 가능한 후보 '00/00/0000'와 같은 값을 의미합니다 '99-99/9999'.
— The Tin Man

1
사용자 정의 정규식이 나쁜 아이디어 일 때의 훌륭한 예입니다!
— Tom Lord

3

더 엄격한 솔루션

원하는 날짜 형식을 지정하면 날짜의 정확성을 확인하는 것이 더 쉽습니다. 그러나 그럼에도 불구하고 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.strptimeformat

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

그것이 바로 제가 찾던 것입니다. 감사합니다!
— Lucas Caton

유효한 날짜 인 "2019-1-1"과 같은 경우에는 실패하지만 strftime은 2019-01-01
— saGii

지정된 형식에 맞지 않는 @saGii (iso8601-참조 Date.today().iso8601) %m제로 패딩입니다. 다른 것을 원한다면 ruby-doc.org/stdlib-2.4.0/libdoc/date/rdoc/…를
— Nathan Long

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

이 String 클래스 용 추가 기능을 사용하면 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에서 예외가 발생하지 않았습니다.

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

config [: dates] = "12 / 10 / 2012,05 / 09 / 1520"인 경우 true 또는 false를 반환합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.