DateTime 클래스
DateTime 클래스
DateTime
Date의 서브클래스로, 날짜, 시, 분, 초, 오프셋을 쉽게 다루는 클래스예요.
DateTime 클래스는 deprecated로 간주돼요. Time 클래스를 사용하세요.
DateTime은 윤초(leap second)를 고려하지 않고, 서머타임 규칙도 추적하지 않아요.
DateTime 객체는 DateTime::new, DateTime::jd, DateTime::ordinal, DateTime::commercial, DateTime::parse, DateTime::strptime, DateTime::now, Time#to_datetime 등으로 만들어져요.
require 'date'
DateTime.new(2001,2,3,4,5,6)
#=> #<DateTime: 2001-02-03T04:05:06+00:00 ...>
day, hour, minute, second의 마지막 요소는 분수 숫자일 수 있어요. 분수 숫자의 정밀도는 최대 나노초로 가정돼요.
DateTime.new(2001,2,3.5)
#=> #<DateTime: 2001-02-03T12:00:00+00:00 ...>
선택적 인자인 오프셋(offset)은 로컬 시간과 UTC 사이의 차이를 나타내요. 예를 들어 Rational(3,24)는 UTC보다 3시간 앞임을, Rational(-5,24)는 UTC보다 5시간 뒤임을 뜻해요. 오프셋은 -1부터 +1 사이여야 하고, 그 정밀도는 최대 초로 가정돼요. 기본값은 0(UTC와 같음)이에요.
DateTime.new(2001,2,3,4,5,6,Rational(3,24))
#=> #<DateTime: 2001-02-03T04:05:06+03:00 ...>
오프셋은 문자열 형태도 받아요.
DateTime.new(2001,2,3,4,5,6,'+03:00')
#=> #<DateTime: 2001-02-03T04:05:06+03:00 ...>
선택적 인자인 달력 개혁일(day of calendar reform, start)은 율리우스 일수(Julian day number)를 나타내며, 2298874부터 2426355 사이 또는 음/양의 무한대여야 해요. 기본값은 Date::ITALY(2299161=1582-10-15)예요.
DateTime 객체는 다양한 메서드를 가져요. 각 참조 문서를 보세요.
d = DateTime.parse('3rd Feb 2001 04:05:06+03:30')
#=> #<DateTime: 2001-02-03T04:05:06+03:30 ...>
d.hour #=> 4
d.min #=> 5
d.sec #=> 6
d.offset #=> (7/48)
d.zone #=> "+03:30"
d += Rational('1.5')
#=> #<DateTime: 2001-02-04%16:05:06+03:30 ...>
d = d.new_offset('+09:00')
#=> #<DateTime: 2001-02-04%21:35:06+09:00 ...>
d.strftime('%I:%M:%S %p')
#=> "09:35:06 PM"
d > DateTime.new(1999)
#=> true
언제 DateTime를 쓰고 언제 Time을 써야 할까?
셰익스피어와 세르반테스가 역사상 같은 날 죽었다는 건 흔한 오해예요. 그래서 유네스코가 이 사실 때문에 4월 23일을 세계 책의 날로 정했을 정도죠. 하지만 영국은 아직 그레고리력 개혁을 채택하지 않았기 때문에(1752년까지), 그들의 죽음은 실제로 10일 차이가 나요. Ruby의 Time 클래스는 선제적(proleptic) 그레고리력을 구현하고 달력 개혁 개념이 없으므로 Time 객체로는 이것을 표현할 방법이 없어요. 이때 DateTime이 등장해요:
shakespeare = DateTime.iso8601('1616-04-23', Date::ENGLAND)
#=> Tue, 23 Apr 1616 00:00:00 +0000
cervantes = DateTime.iso8601('1616-04-23', Date::ITALY)
#=> Sat, 23 Apr 1616 00:00:00 +0000
이미 뭔가 이상하다는 걸 알 수 있어요 - 요일이 다르죠. 더 나아가 보면:
cervantes == shakespeare
#=> false
(shakespeare - cervantes).to_i
#=> 10
이것은 실제로 그들이 10일 차이로 죽었다는 걸 보여줘요(실제로는 11일인데, 세르반테스는 하루 먼저 죽었지만 23일에 묻혔기 때문이에요). gregorian 메서드를 사용해 변환하면 셰익스피어의 실제 사망일을 볼 수 있어요:
shakespeare.gregorian
#=> Tue, 03 May 1616 00:00:00 +0000
그래서 Stratford-upon-Avon에서 4월 23일에 열리는 모든 기념행사는 영국이 지금 그레고리력을 사용하므로 사실 잘못된 날짜라는 주장이 있어요. 개혁일 경계를 넘어갈 때 왜 그런지 알 수 있어요:
# 셰익스피어 탄생 기념일 1751년부터 시작
shakespeare = DateTime.iso8601('1751-04-23', Date::ENGLAND)
#=> Tue, 23 Apr 1751 00:00:00 +0000
# 1752년은 윤년이고 4월 23일은 2월 29일 이후이므로 366일을 더해요
shakespeare + 366
#=> Thu, 23 Apr 1752 00:00:00 +0000
# 1753년 기념일로 가기 위해 다시 365일을 더해요
shakespeare + 366 + 365
#=> Fri, 04 May 1753 00:00:00 +0000
보시다시피 셰익스피어 생일 이후의 태양년 수를 정확히 추적한다면, 올바른 기념일은 4월 23일이 아니라 5월 4일이 돼요.
그럼 Ruby에서 언제 DateTime을 쓰고 언제 Time을 써야 할까요? 거의 확실히 여러분 앱이 현재 날짜와 시간을 다루기 때문에 Time을 쓰고 싶을 거예요. 하지만 역사적 맥락의 날짜와 시간을 다뤄야 한다면 유네스코와 같은 실수를 피하려고 DateTime을 쓰고 싶을 거예요. 타임존까지 다뤄야 한다면 행운을 빌어요 - 19세기가 되어서야 철도의 도입으로 표준시와 결국 타임존이 필요해졌으므로, 아마 지역 태양시를 다루게 될 거라는 점만 명심하세요.
출처: Ruby 3.3 API
본문
클래스 메서드
_strptime(string[, format='%FT%T%z']) → hash— 주어진 템플릿으로 날짜·시간 표현을 파싱하고, 파싱된 요소의 해시를 돌려줘요._strptime은strftime과 달리 플래그와 너비 지정을 지원하지 않아요. strptime(3)과strftime도 참고.civil(*args)—DateTime.new와 같아요.commercial([cwyear=-4712[, cweek=1[, cwday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]]) → datetime— 주어진 주 날짜(week date)를 나타내는DateTime객체를 만들어요.
DateTime.commercial(2001) #=> #<DateTime: 2001-01-01T00:00:00+00:00 ...>
DateTime.commercial(2002) #=> #<DateTime: 2001-12-31T00:00:00+00:00 ...>
DateTime.commercial(2001,5,6,4,5,6,'+7')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=Date::ITALY]) → datetime— RFC 2616 형식에 따라 문자열을 파싱해서 새DateTime객체를 만들어요.
DateTime.httpdate('Sat, 03 Feb 2001 04:05:06 GMT')
#=> #<DateTime: 2001-02-03T04:05:06+00:00 ...>
문자열 길이가 limit보다 길면 ArgumentError를 발생시켜요. limit: nil을 넘기면 이 검사를 막을 수 있지만, 파싱에 오래 걸릴 수 있음을 주의하세요.
iso8601(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) → datetime— 전형적인 ISO 8601 형식에 따라 문자열을 파싱해서 새DateTime객체를 만들어요.
DateTime.iso8601('2001-02-03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.iso8601('20010203T040506+0700')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.iso8601('2001-W05-6T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
jd([jd=0[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]) → datetime— 주어진 연대적 율리우스 일수를 나타내는DateTime객체를 만들어요.
DateTime.jd(2451944) #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...>
DateTime.jd(2451945) #=> #<DateTime: 2001-02-04T00:00:00+00:00 ...>
DateTime.jd(Rational('0.5'))
#=> #<DateTime: -4712-01-01T12:00:00+00:00 ...>
jisx0301(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) → datetime— 전형적인 JIS X 0301 형식에 따라 문자열을 파싱해서 새DateTime객체를 만들어요.
DateTime.jisx0301('H13.02.03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
시대 표기가 없는 연도의 레거시 형식에서는 Heisei로 가정돼요.
DateTime.jisx0301('13.02.03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
json_create(object)—as_json참고.new(*args)—DateTime.new와 같아요.now([start=Date::ITALY]) → datetime— 현재 시간을 나타내는DateTime객체를 만들어요.
DateTime.now #=> #<DateTime: 2011-06-11T21:20:44+09:00 ...>
ordinal([year=-4712[, yday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]) → datetime— 주어진 서수 날짜(ordinal date)를 나타내는DateTime객체를 만들어요.
DateTime.ordinal(2001,34) #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...>
DateTime.ordinal(2001,34,4,5,6,'+7')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.ordinal(2001,-332,-20,-55,-54,'+7')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
parse(string='-4712-01-01T00:00:00+00:00'[, comp=true[, start=Date::ITALY]], limit: 128) → datetime— 주어진 날짜·시간 표현을 파싱해서DateTime객체를 만들어요. 이 메서드는 검증기(validator) 기능을 하지 않아요. 입력 문자열이 유효한 형식과 엄격히 일치하지 않으면 이해하기 어려운 결과가 나올 수 있어요. 가능하면 이 메서드 대신DateTime.strptime을 고려하세요. 선택적 두 번째 인자가 true이고 감지된 연도가 "00"~"99" 범위에 있으면 full year로 만들어요.
DateTime.parse('2001-02-03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.parse('20010203T040506+0700')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.parse('3rd Feb 2001 04:05:06 PM')
#=> #<DateTime: 2001-02-03T16:05:06+00:00 ...>
rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY], limit: 128) → datetime(rfc822의 별칭) — 전형적인 RFC 2822 형식에 따라 문자열을 파싱해서 새DateTime객체를 만들어요.
DateTime.rfc2822('Sat, 3 Feb 2001 04:05:06 +0700')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) → datetime— 전형적인 RFC 3339 형식에 따라 문자열을 파싱해서 새DateTime객체를 만들어요.
DateTime.rfc3339('2001-02-03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
strptime([string='-4712-01-01T00:00:00+00:00'[, format='%FT%T%z'[ ,start=Date::ITALY]]]) → datetime— 주어진 템플릿으로 날짜·시간 표현을 파싱해서DateTime객체를 만들어요.strptime은strftime과 달리 플래그와 너비 지정을 지원하지 않아요.
DateTime.strptime('2001-02-03T04:05:06+07:00', '%Y-%m-%dT%H:%M:%S%z')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.strptime('03-02-2001 04:05:06 PM', '%d-%m-%Y %I:%M:%S %p')
#=> #<DateTime: 2001-02-03T16:05:06+00:00 ...>
DateTime.strptime('2001-W05-6T04:05:06+07:00', '%G-W%V-%uT%H:%M:%S%z')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.strptime('-1', '%s')
#=> #<DateTime: 1969-12-31T23:59:59+00:00 ...>
DateTime.strptime('-1000', '%Q')
#=> #<DateTime: 1969-12-31T23:59:59+00:00 ...>
DateTime.strptime('sat3feb014pm+7', '%a%d%b%y%H%p%z')
#=> #<DateTime: 2001-02-03T16:00:00+07:00 ...>
xmlschema(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) → datetime— 전형적인 XML Schema 형식에 따라 문자열을 파싱해서 새DateTime객체를 만들어요.
DateTime.xmlschema('2001-02-03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
인스턴스 메서드
as_json(*)—DateTime#as_json과DateTime.json_create메서드로DateTime객체를 직렬화/역직렬화할 수 있어요.DateTime#as_json은self를 나타내는 해시를 돌려줘요.
require 'json/add/datetime'
x = DateTime.now.as_json
# => {"json_class"=>"DateTime", "y"=>2023, "m"=>11, "d"=>21, "sg"=>2299161.0}
deconstruct_keys(array_of_names_or_nil) → hash— 패턴 매칭에 쓰이도록 이름/값 쌍의 해시를 돌려줘요. 가능한 키는:year,:month,:day,:wday,:yday,:hour,:min,:sec,:sec_fraction,:zone이에요.
dt = DateTime.new(2022, 10, 5, 13, 30)
if d in wday: 1..5, hour: 10..18 # uses deconstruct_keys underneath
puts "Working time"
end
#=> prints "Working time"
case dt
in year: ...2022
puts "too old"
in month: ..9
puts "quarter 1-3"
in wday: 1..5, month:
puts "working day in month #{month}"
end
#=> prints "working day in month 10"
hour → integer— (0..23) 범위의 시를 돌려줘요:DateTime.new(2001, 2, 3, 4, 5, 6).hour # => 4iso8601([n=0]) → string(xmlschema의 별칭) — strftime('%FT%T%:z')와 동등해요. 선택적 인자n은 소수 초의 자릿수예요.
DateTime.parse('2001-02-03T04:05:06.123456789+07:00').iso8601(9)
#=> "2001-02-03T04:05:06.123456789+07:00"
jisx0301([n=0]) → string— JIS X 0301 형식의 문자열을 돌려줘요. 선택적 인자n은 소수 초의 자릿수예요.
DateTime.parse('2001-02-03T04:05:06.123456789+07:00').jisx0301(9)
#=> "H13.02.03T04:05:06.123456789+07:00"
min → integer(minute의 별칭) — (0..59) 범위의 분을 돌려줘요:DateTime.new(2001, 2, 3, 4, 5, 6).min # => 5new_offset([offset=0]) → date— self를 복제하고 오프셋을 재설정해요.
d = DateTime.new(2001,2,3,4,5,6,'-02:00')
#=> #<DateTime: 2001-02-03T04:05:06-02:00 ...>
d.new_offset('+09:00') #=> #<DateTime: 2001-02-03T15:05:06+09:00 ...>
offset → rational— 오프셋을 돌려줘요:DateTime.parse('04pm+0730').offset #=> (5/16)rfc3339([n=0]) → string— strftime('%FT%T%:z')와 동등해요. 선택적 인자n은 소수 초의 자릿수예요.sec → integer(second의 별칭) — (0..59) 범위의 초를 돌려줘요:DateTime.new(2001, 2, 3, 4, 5, 6).sec # => 6sec_fraction → rational(second_fraction의 별칭) — (Rational(0, 1)…Rational(1, 1)) 범위의 초의 분수 부분을 돌려줘요:DateTime.new(2001, 2, 3, 4, 5, 6.5).sec_fraction # => (1/2)strftime(format = '%FT%T%:z') → string— 주어진format에 따라 포맷된self의 문자열 표현을 돌려줘요.
DateTime.now.strftime # => "2022-07-01T11:03:19-05:00"
to_date → date— self를 나타내는Date객체를 돌려줘요.to_datetime → self— self를 돌려줘요.to_json(*args)—self를 나타내는JSON문자열을 돌려줘요.
require 'json/add/datetime'
puts DateTime.now.to_json
# {"json_class":"DateTime","y":2023,"m":11,"d":21,"sg":2299161.0}
to_s → string— ISO 8601 형식의 문자열을 돌려줘요. (확장 표현은 사용하지 않아요.)
DateTime.new(2001,2,3,4,5,6,'-7').to_s
#=> "2001-02-03T04:05:06-07:00"
to_time → time— self를 나타내는Time객체를 돌려줘요.zone → string— 타임존을 돌려줘요:DateTime.parse('04pm+0730').zone #=> "+07:30"
더 알아보기
- Date —
DateTime의 슈퍼클래스 - 날짜와 시간의 형식](https://docs.ruby-lang.org/en/3.3/strftime_rdoc.html) —
strftime형식