Ruby에서 DateTime 및 Time으로 /에서 변환


132

Ruby에서 DateTime과 Time 객체를 어떻게 변환합니까?


1
이것이 별도의 질문인지 확실하지 않지만 날짜와 시간을 어떻게 변환합니까?
Andrew Grimm 4

8
최신 버전의 루비에서는 허용되는 답변과 가장 높은 답변이 더 이상 정확하지 않습니다. 답변을 참조하십시오 @theTinMan로 하고 @PatrickMcKenzie에 의해 아래를.
Phrogz

답변:


50

약간 다른 전환이 필요합니다.

변환하는 방법 Time DateTime다음과 같이 시간의 수업을 개정 할 수 있습니다 :

require 'date'
class Time
  def to_datetime
    # Convert seconds + microseconds into a fractional number of seconds
    seconds = sec + Rational(usec, 10**6)

    # Convert a UTC offset measured in minutes to one measured in a
    # fraction of a day.
    offset = Rational(utc_offset, 60 * 60 * 24)
    DateTime.new(year, month, day, hour, min, seconds, offset)
  end
end

날짜와 유사하게 조정하면 변환하게됩니다 DateTime Time .

class Date
  def to_gm_time
    to_time(new_offset, :gm)
  end

  def to_local_time
    to_time(new_offset(DateTime.now.offset-offset), :local)
  end

  private
  def to_time(dest, method)
    #Convert a fraction of a day to a number of microseconds
    usec = (dest.sec_fraction * 60 * 60 * 24 * (10**6)).to_i
    Time.send(method, dest.year, dest.month, dest.day, dest.hour, dest.min,
              dest.sec, usec)
  end
end

현지 시간과 GM / UTC 시간 중에서 선택해야합니다.

위의 코드 스 니펫은 모두 O'Reilly의 Ruby Cookbook 에서 가져 왔습니다 . 그들의 코드 재사용 정책은 이것을 허용합니다.


5
DateTime # sec_fraction은 1 초에 밀리 초 수를 반환하는 1.9에서 중단됩니다. 1.9의 경우 : usec = dest.sec_fraction * 10 ** 6
dkubb

185
require 'time'
require 'date'

t = Time.now
d = DateTime.now

dd = DateTime.parse(t.to_s)
tt = Time.parse(d.to_s)

13
+1 이것은 가장 효율적으로 실행되지는 않지만 작동하고 간결하며 읽기 쉽습니다.
Walt Jones

6
불행히도 이것은 현지 시간을 다룰 때만 실제로 작동합니다. 다른 시간대로 DateTime 또는 Time으로 시작하면 구문 분석 기능이 현지 시간대로 변환됩니다. 기본적으로 원래 시간대가 손실됩니다.
Bernard

6
루비 1.9.1부터 DateTime.parse는 시간대를 유지합니다. Time.parse는 시간대를 보존하지 않습니다. 시간대는 POSIX 표준 time_t를 나타 내기 때문에 에포크와의 정수 차이라고 생각합니다. Time으로의 변환은 모두 같은 행동을 가져야합니다.
anshul

1
네가 옳아. DateTime.parse는 1.9.1에서 작동하지만 Time.parse에서는 작동하지 않습니다. 어쨌든 오류가 발생하기 쉽고 (일관됨) DateTime.new (...) 및 Time.new (..)를 사용하는 것이 더 빠릅니다. 샘플 코드에 대한 내 대답을 참조하십시오.
Bernard

1
안녕하세요 @anshul. 나는 내가 말하는 것을 암시하지 않는다 :-). Time.parse ()를 사용할 때 시간대 정보가 유지되지 않습니다. 테스트하기 쉽습니다. 위 코드에서 d = DateTime.now를 d = DateTime.new (2010,01,01, 10,00,00, Rational (-2, 24))로 바꾸십시오. tt는 현재 날짜 d를 현지 시간대로 변환하여 표시합니다. 날짜 산술을 계속 수행 할 수 있으며 원래 tz 정보를 제외한 모든 정보가 손실됩니다. 이 정보는 날짜와 관련된 내용이므로 종종 중요합니다. 여기를보십시오 : stackoverflow.com/questions/279769/…
Bernard Bernard

63

루비 생태계의 상태에 대한 업데이트로서 Date, DateTime그리고 Time지금은 다양한 클래스 사이의 변환 방법이있다. Ruby 1.9.2 이상 사용 :

pry
[1] pry(main)> ts = 'Jan 1, 2000 12:01:01'
=> "Jan 1, 2000 12:01:01"
[2] pry(main)> require 'time'
=> true
[3] pry(main)> require 'date'
=> true
[4] pry(main)> ds = Date.parse(ts)
=> #<Date: 2000-01-01 (4903089/2,0,2299161)>
[5] pry(main)> ds.to_date
=> #<Date: 2000-01-01 (4903089/2,0,2299161)>
[6] pry(main)> ds.to_datetime
=> #<DateTime: 2000-01-01T00:00:00+00:00 (4903089/2,0,2299161)>
[7] pry(main)> ds.to_time
=> 2000-01-01 00:00:00 -0700
[8] pry(main)> ds.to_time.class
=> Time
[9] pry(main)> ds.to_datetime.class
=> DateTime
[10] pry(main)> ts = Time.parse(ts)
=> 2000-01-01 12:01:01 -0700
[11] pry(main)> ts.class
=> Time
[12] pry(main)> ts.to_date
=> #<Date: 2000-01-01 (4903089/2,0,2299161)>
[13] pry(main)> ts.to_date.class
=> Date
[14] pry(main)> ts.to_datetime
=> #<DateTime: 2000-01-01T12:01:01-07:00 (211813513261/86400,-7/24,2299161)>
[15] pry(main)> ts.to_datetime.class
=> DateTime

1
DateTime.to_time은 DateTime을 반환합니다. 1.9.3p327 :007 > ts = '2000-01-01 12:01:01 -0700' => "2000-01-01 12:01:01 -0700" 1.9.3p327 :009 > dt = ts.to_datetime => Sat, 01 Jan 2000 12:01:01 -0700 1.9.3p327 :010 > dt.to_time => Sat, 01 Jan 2000 12:01:01 -0700 1.9.3p327 :011 > dt.to_time.class => DateTime
Jesse Clark

죄송합니다. : 그냥이 루비 레일에 문제가되지 루비 문제가 있음을 깨달았다 stackoverflow.com/questions/11277454/... . 그들은 심지어 2.x 라인에서이 방법에 대해 버그를 제기하여 "수정하지 않음"으로 표시했습니다. 끔찍한 결정 IMHO. Rails의 동작은 근본적인 Ruby 인터페이스를 완전히 파괴합니다.
Jesse Clark

12

불행하게도 DateTime.to_time, Time.to_datetimeTime.parse기능은 시간대 정보를 유지하지 않습니다. 변환하는 동안 모든 것이 현지 시간대로 변환됩니다. 날짜 산술은 여전히 ​​작동하지만 원래 시간대로 날짜를 표시 할 수 없습니다. 그 맥락 정보는 종종 중요합니다. 예를 들어, 뉴욕에서 영업 시간 동안 수행 된 거래를 보려면 호주의 현지 시간대 (뉴질랜드보다 12 시간 빠름)가 아닌 원래 시간대로 표시되는 것을 선호합니다.

아래의 변환 방법은 해당 tz 정보를 유지합니다.

Ruby 1.8의 경우 Gordon Wilson의 답변을보십시오 . 오래되고 신뢰할 수있는 Ruby Cookbook에서 가져온 것입니다.

Ruby 1.9의 경우 약간 더 쉽습니다.

require 'date'

# Create a date in some foreign time zone (middle of the Atlantic)
d = DateTime.new(2010,01,01, 10,00,00, Rational(-2, 24))
puts d

# Convert DateTime to Time, keeping the original timezone
t = Time.new(d.year, d.month, d.day, d.hour, d.min, d.sec, d.zone)
puts t

# Convert Time to DateTime, keeping the original timezone
d = DateTime.new(t.year, t.month, t.day, t.hour, t.min, t.sec, Rational(t.gmt_offset / 3600, 24))
puts d

이것은 다음을 인쇄합니다

2010-01-01T10:00:00-02:00
2010-01-01 10:00:00 -0200
2010-01-01T10:00:00-02:00

시간대를 포함하여 전체 원래 DateTime 정보가 유지됩니다.


2
시간은 복잡하지만 다른 내장 시간 클래스간에 내장 변환을 제공하지 않는다는 변명의 여지가 없습니다. BC 4713 BC에 대해 UNIX time_t를 얻으려고 시도하면 (BigNum 음수 값이 더 좋을지라도) RangeException을 발생시킬 수 있지만 최소한 이에 대한 방법을 제공하십시오.
Mark Reed

1
Time#to_datetime나를 위해 tz를 보존하는 것으로 보입니다 :Time.local(0).to_datetime.zone #=> "-07:00"; Time.gm(0).to_datetime.zone #=> "+00:00"
Phrogz

@Phrogz UTC 오프셋은 표준 시간대와 다릅니다. 하나는 일정하고 다른 하나는 일광 절약 시간제를 위해 연중 다른 시간에 변경 될 수 있습니다. DateTime에는 영역이 없으며 DST를 무시합니다. 시간은이를 고려하지만 "로컬"(시스템 환경) TZ에서만.
Andrew Vit

1

Gordon Wilson 솔루션을 개선하는 방법은 다음과 같습니다.

def to_time
  #Convert a fraction of a day to a number of microseconds
  usec = (sec_fraction * 60 * 60 * 24 * (10**6)).to_i
  t = Time.gm(year, month, day, hour, min, sec, usec)
  t - offset.abs.div(SECONDS_IN_DAY)
end

시간대를 잃어버린 UTC로 같은 시간을 얻습니다 (불행히도)

또한 루비 1.9가 있다면 to_time방법을 사용해보십시오.


0

이러한 변환을 수행하는 동안 한 개체에서 다른 개체로 변환하는 동안 시간대의 동작을 고려해야합니다. 이 stackoverflow 게시물 에서 좋은 메모와 예제를 발견 했습니다 .

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