web-dev-qa-db-ja.com

RubyのDateTimeおよびTimeへ/からの変換

RubyでDateTimeとTimeオブジェクトをどのように変換しますか?

129
Readonly

わずかに異なる2つの変換が必要です。

TimeからDateTimeに変換するには、次のようにTimeクラスを修正できます。

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

日付に対する同様の調整により、DateTimeTimeに変換できます。

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 から取られています。コードの再利用 policy はこれを許可します。

48
Gordon Wilson
require 'time'
require 'date'

t = Time.now
d = DateTime.now

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

Rubyエコシステムの状態の更新として、DateDateTimeおよび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
61
the Tin Man

残念ながら、DateTime.to_time, Time.to_datetimeおよびTime.parse関数はタイムゾーン情報を保持しません。変換中にすべてがローカルタイムゾーンに変換されます。日付計算は引き続き機能しますが、元のタイムゾーンで日付を表示することはできません。そのコンテキスト情報はしばしば重要です。たとえば、ニューヨークの営業時間中に実行されたトランザクションを表示したい場合、オーストラリアのローカルタイムゾーン(ニューヨークの12時間前)ではなく、元のタイムゾーンで表示されることを好みます。

以下の変換方法は、そのtz情報を保持します。

Ruby 1.8の場合、 Gordon Wilson's answer を見てください。それは古き良き信頼できる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情報が保持されます。

10
Bernard

ゴードン・ウィルソンのソリューションを改善するために、ここに私の試みがあります:

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で同じ時間を取得し、タイムゾーンを失います(残念ながら)

また、Ruby 1.9がある場合は、to_timeメソッドを試してください。

1
Mildred