转换为/从日期时间和Ruby中的时间

问题描述:

如何在Ruby中的DateTime和Time对象之间进行转换?转换为/从日期时间和Ruby中的时间

+1

我不知道这应该是一个单独的问题,但你如何转换日期和时间? – 2010-07-15 04:31:50

+8

在现代版本的Ruby中,被接受且评分最高的答案不再是最准确的答案。看到的答案[由@theTinMan](http://*.com/a/8511699/405017)和[由@PatrickMcKenzie]以下(http://*.com/a/280026/405017)。 – Phrogz 2012-03-07 20:16:34

您需要两个略有不同的转换。

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 

类似的调整时间会让你转换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允许这样做。

+5

这将在1.9上中断,其中DateTime#sec_fraction返回一秒中的毫秒数。对于1.9你想要使用:usec = dest.sec_fraction * 10 ** 6 – dkubb 2011-03-14 21:52:17

require 'time' 
require 'date' 

t = Time.now 
d = DateTime.now 

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

+1这可能不是最有效的执行,但它的工作原理,简洁并且非常可读。 – 2009-06-16 22:20:18

+6

不幸的是,这只在处理当地时间时才有效。如果以具有不同时区的DateTime或Time开始,则解析函数将转换为本地时区。你基本上失去了原来的时区。 – Alkaline 2010-08-18 14:20:28

不幸的是,DateTime.to_time, Time.to_datetimeTime.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 

的完整的原始日期时间信息包括时区保持。

作为对Ruby生态系统状态的更新,Date,DateTimeTime现在具有在各种类之间转换的方法。使用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 

提高戈登·威尔逊的解决方案,这是我的尝试:

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方法