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


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.