[ruby] Ruby에서 DateTime과 시간의 차이

Ruby의 클래스 DateTimeTime클래스 의 차이점은 무엇이며 어떤 요소를 선택해야합니까?



답변

최신 버전의 Ruby (2.0+)는 실제로 두 클래스간에 큰 차이가 없습니다. 일부 라이브러리는 역사적 이유로 하나 또는 다른 라이브러리를 사용하지만 새로운 코드가 반드시 필요한 것은 아닙니다. 일관성을 위해 하나를 선택하는 것이 가장 좋을 것이므로 라이브러리가 기대하는 것과 맞물려보십시오. 예를 들어 ActiveRecord는 DateTime을 선호합니다.

Ruby 1.9 이전 버전과 많은 시스템에서 Time은 POSIX 표준 time_t값을 기준으로 한 얇은 랩퍼 인 UTC 1970 년 1 월 1 일 이후의 시간 (초)을 설명하는 32 비트 부호있는 값으로 표시됩니다 .

Time.at(0x7FFFFFFF)
# => Mon Jan 18 22:14:07 -0500 2038
Time.at(-0x7FFFFFFF)
# => Fri Dec 13 15:45:53 -0500 1901

최신 버전의 Ruby는 오류없이 더 큰 값을 처리 할 수 ​​있습니다.

DateTime은 연도, 월, 일,시, 분 및 초가 개별적으로 저장되는 달력 기반 접근 방식입니다. 이것은 SQL 표준 DATETIME 필드에 대한 랩퍼 역할을하는 Ruby on Rails 구성입니다. 여기에는 임의의 날짜가 포함되며 일반적으로 표현 범위가 매우 크기 때문에 거의 모든 시점을 나타낼 수 있습니다.

DateTime.new
# => Mon, 01 Jan -4712 00:00:00 +0000

따라서 DateTime이 Aristotle의 블로그 게시물을 처리 할 수 ​​있다는 것이 안심입니다.

하나를 선택할 때, 차이점은 이제 다소 주관적입니다. 역사적으로 DateTime은 달력 방식으로이를 조작하기위한 더 나은 옵션을 제공했지만 이러한 방법 중 다수는 적어도 Rails 환경 내에서 Time으로 이식되었습니다.


답변

[2018 년 7 월 편집]

아래의 모든 사항은 Ruby 2.5.1에서도 여전히 유효합니다. 로부터 참조 문서 :

DateTime은 윤초를 고려하지 않으며 하계 시간 규칙을 추적하지 않습니다.

전에이 스레드에서 언급되지 않은 것은 몇 가지 장점 중 하나입니다. DateTime달력 개혁을 알고 있지만 Time그렇지는 않습니다.

[…] 루비의 Time 클래스는 다독 그레고리력을 구현하며 달력 개혁의 개념은 없습니다.

참조 문서는 Time과거, 현재 또는 미래의 날짜 / 시간을 독점적으로 다룰 때 사용할 것을 권장하고 DateTime, 예를 들어 셰익스피어의 생일을 정확하게 변환해야하는 경우 에만 사용하도록 권장 합니다. (강조 추가)

그렇다면 Ruby에서 DateTime을 언제 사용해야하고 언제 Time을 사용해야합니까? 앱이 현재 날짜와 시간을 처리하고 있기 때문에 시간을 사용하는 것이 좋습니다. 그러나 과거 상황에서 날짜와 시간을 처리해야하는 경우 DateTime […] 을 사용하는 것이 좋습니다 . 시간대를 다뤄야한다면 운이 좋을 것입니다. 19 세기까지는 철도 도입으로 표준시가 필요하지 않았기 때문에 현지 태양 시간을 다룰 것입니다. 그리고 결국 시간대.

[/ 2018 년 7 월 편집]

루비 2.0부터 다른 답변의 정보 대부분이 오래되었습니다.

특히, Time지금은 사실상 약속이 없습니다. Epoch에서 63 비트 이상 떨어져있을 수 있습니다.

irb(main):001:0> RUBY_VERSION
=> "2.0.0"
irb(main):002:0> Time.at(2**62-1).utc # within Integer range
=> 146138514283-06-19 07:44:38 UTC
irb(main):003:0> Time.at(2**128).utc # outside of Integer range
=> 10783118943836478994022445751222-08-06 08:03:51 UTC
irb(main):004:0> Time.at(-2**128).utc # outside of Integer range
=> -10783118943836478994022445747283-05-28 15:55:44 UTC

더 큰 값을 사용하는 유일한 결과는 성능이어야합니다. 이는 Integers (vs. Bignum( Integer범위 밖의 값 ) 또는 Rationals (나노초를 추적 할 때 )를 사용할 때 더 좋습니다 ) :

Ruby 1.9.2부터 Time 구현은 부호있는 63 비트 정수, Bignum 또는 Rational을 사용합니다. 정수는 1823-11-12에서 2116-02-20을 나타낼 수있는 Epoch 이후 수 나노초입니다. Bignum 또는 Rational을 사용하면 (1823 이전, 2116 후, 나노초 미만), 정수를 사용할 때와 같이 시간이 느리게 작동합니다. ( http://www.ruby-doc.org/core-2.1.0/Time.html )

다시 말해, 내가 이해하는 한, DateTime더 이상 광범위한 잠재적 가치를 다루지 않습니다Time .

또한 앞에서 언급하지 않은 두 가지 제한 사항에 DateTime유의해야합니다.

DateTime은 윤초를 고려하지 않으며 하계 시간 규칙을 추적하지 않습니다. ( http://www.ruby-doc.org/stdlib-2.1.0/libdoc/date/rdoc/Date.html#class-Date-label-DateTime )

첫째, DateTime윤초의 개념이 없습니다.

irb(main):001:0> RUBY_VERSION
=> "2.0.0"
irb(main):002:0> require "date"
=> true
irb(main):003:0> t = Time.new(2012,6,30,23,59,60,0)
=> 2012-06-30 23:59:60 +0000
irb(main):004:0> dt = t.to_datetime; dt.to_s
=> "2012-06-30T23:59:59+00:00"
irb(main):005:0> t == dt.to_time
=> false
irb(main):006:0> t.to_i
=> 1341100824
irb(main):007:0> dt.to_time.to_i
=> 1341100823

위의 예제가 (으)로 작동 Time하려면 OS가 윤초를 지원해야하고 시간대 정보를 올바르게 설정해야합니다 (예 : TZ=right/UTC irb많은 유닉스 시스템에서).

둘째, DateTime시간대에 대한 이해가 매우 제한적이고 특히 일광 절약의 개념이 없습니다 . 시간대를 간단한 UTC + X 오프셋으로 처리합니다.

irb(main):001:0> RUBY_VERSION
=> "2.0.0"
irb(main):002:0> require "date"
=> true
irb(main):003:0> t = Time.local(2012,7,1)
=> 2012-07-01 00:00:00 +0200
irb(main):004:0> t.zone
=> "CEST"
irb(main):005:0> t.dst?
=> true
irb(main):006:0> dt = t.to_datetime; dt.to_s
=> "2012-07-01T00:00:00+02:00"
irb(main):007:0> dt.zone
=> "+02:00"
irb(main):008:0> dt.dst?
NoMethodError: undefined method `dst?' for #<DateTime:0x007f34ea6c3cb8>

시간이 DST로 입력 된 후 DateTime자체 외부의 올바른 오프셋을 추적하지 않고 DST가 아닌 시간대로 변환 될 때 문제가 발생할 수 있습니다 (많은 운영 체제가 실제로이를 대신 할 수 있음).

전반적으로 요즘 Time은 대부분의 응용 프로그램에 더 나은 선택 이라고 말하고 싶습니다 .

또한 더하기의 중요한 차이점에 유의하십시오. Time 객체에 숫자를 추가하면 초 단위로 계산되지만 DateTime에 숫자를 추가하면 일 단위로 계산됩니다.


답변

“차이점”에 대한 대답은 Ruby 표준 라이브러리에서이 질문에 대한 불행한 일반적인 답변 중 하나라고 생각합니다. 두 클래스 / lib는 다른 시간에 다른 사람들에 의해 다르게 만들어졌습니다. Java와 같은 신중하게 계획된 개발과 비교할 때 Ruby의 진화로 인한 커뮤니티 특성의 불행한 결과 중 하나입니다. 개발자는 새로운 기능을 원하지만 기존 API를 밟고 싶지 않기 때문에 새로운 클래스를 만들면됩니다. 최종 사용자에게는이 둘이 존재해야 할 이유가 없습니다.

이것은 일반적으로 소프트웨어 라이브러리의 경우에 해당합니다. 종종 일부 코드 또는 API가 논리적이 아닌 역사적으로 밝혀지는 방식입니다.

유혹은 더 일반적인 것처럼 보이기 때문에 DateTime으로 시작하는 것입니다. 날짜와 시간? 잘못된. 시간은 또한 날짜를 더 잘 수행하며 실제로 DateTime이 할 수없는 시간대를 구문 분석 할 수 있습니다. 또한 더 잘 수행합니다.

나는 어디에서나 시간을 사용하게되었습니다.

안전하기 위해 DateTime 인수를 Timey API로 전달하고 변환하는 경향이 있습니다. 또한 둘 다 내가 관심있는 방법을 가지고 있음을 알고 있다면,이 방법과 같이 시간을 XML로 변환하기 위해 작성한 방법 (XMLTV 파일의 경우)

# Will take a date time as a string or as a Time or DateTime object and
# format it appropriately for xmtlv. 
# For example, the 22nd of August, 2006 at 20 past midnight in the British Summertime
# timezone (i.e. GMT plus one hour for DST) gives: "20060822002000 +0100"
def self.format_date_time(date_time)
  if (date_time.respond_to?(:rfc822)) then
    return format_time(date_time)
  else 
    time = Time.parse(date_time.to_s)
    return format_time(time)
  end    
end

# Note must use a Time, not a String, nor a DateTime, nor Date.
# see format_date_time for the more general version
def self.format_time(time)
  # The timezone feature of DateTime doesn't work with parsed times for some reason
  # and the timezone of Time is verbose like "GMT Daylight Saving Time", so the only
  # way I've discovered of getting the timezone in the form "+0100" is to use 
  # Time.rfc822 and look at the last five chars
  return "#{time.strftime( '%Y%m%d%H%M%S' )} #{time.rfc822[-5..-1]}"
end


답변

ActiveTime 확장을 사용한다고 가정하면 DateTime으로 다른 시간대의 하루 시작 / 종료를 구문 분석하고 계산하는 것이 더 쉽다 는 것을 알았습니다 .

필자의 경우 문자열로받은 사용자의 현지 시간 (예 : “2012-10-10 10:10 +0300”)을 기준으로 사용자 시간대 (임의)에서 하루의 끝을 계산해야했습니다.

DateTime을 사용하면 간단합니다.

irb(main):034:0> DateTime.parse('2012-10-10 10:10 +0300').end_of_day
=> Wed, 10 Oct 2012 23:59:59 +0300
# it preserved the timezone +0300

이제 Time과 같은 방식으로 시도해 봅시다.

irb(main):035:0> Time.parse('2012-10-10 10:10 +0300').end_of_day
=> 2012-10-10 23:59:59 +0000
# the timezone got changed to the server's default UTC (+0000), 
# which is not what we want to see here.

실제로, 시간은 파싱하기 전에 시간대를 알아야합니다 (또한 Time.zone.parse아닙니다 Time.parse).

irb(main):044:0> Time.zone = 'EET'
=> "EET"
irb(main):045:0> Time.zone.parse('2012-10-10 10:10 +0300').end_of_day
=> Wed, 10 Oct 2012 23:59:59 EEST +03:00

따라서이 경우 DateTime을 사용하는 것이 훨씬 쉽습니다.


답변

사용자 지정 인스턴스화를 사용하여 시간대를 다르게 처리하는 방법을 고려하십시오.

irb(main):001:0> Time.new(2016,9,1)
=> 2016-09-01 00:00:00 -0400
irb(main):002:0> DateTime.new(2016,9,1)
=> Thu, 01 Sep 2016 00:00:00 +0000
irb(main):003:0> Time.new(2016,9,1).to_i
=> 1472702400
irb(main):004:0> DateTime.new(2016,9,1).to_i
=> 1472688000

시간 범위 등을 만들 때 까다로울 수 있습니다.


답변

경우에 따라 동작이 매우 다른 것 같습니다.

Time.parse("Ends from 28 Jun 2018 12:00 BST").utc.to_s

“2018-06-28 09:00:00 UTC”

Date.parse("Ends from 28 Jun 2018 12:00 BST").to_time.utc.to_s

“2018-06-27 21:00:00 UTC”

DateTime.parse("Ends from 28 Jun 2018 12:00 BST").to_time.utc.to_s

“2018-06-28 11:00:00 UTC”


답변

Niels Ganser의 답변 외에도 다음과 같은 주장을 고려할 수 있습니다.

참고 루비 스타일 가이드는 아주 명확에서 위치를 상태 :

날짜 시간 없음

기록 일정 변경을 설명해야하는 경우가 아니면 DateTime을 사용하지 마십시오. 그렇게하면 의도를 명확하게 나타 내기 위해 start 인수를 명시 적으로 지정하십시오.

# bad - uses DateTime for current time
DateTime.now

# good - uses Time for current time
Time.now

# bad - uses DateTime for modern date
DateTime.iso8601('2016-06-29')

# good - uses Date for modern date
Date.iso8601('2016-06-29')

# good - uses DateTime with start argument for historical date
DateTime.iso8601('1751-04-23', Date::ENGLAND)