2009-08-11 26 views

Trả lời

161

Phiên bản mới hơn của Ruby (2.0+) không thực sự có sự khác biệt đáng kể giữa hai lớp. Một số thư viện sẽ sử dụng một hoặc một vì lý do lịch sử, nhưng mã mới không nhất thiết cần phải được quan tâm. Chọn một cho nhất quán có lẽ là tốt nhất, vì vậy hãy thử và lưới với những gì các thư viện của bạn mong đợi. Ví dụ, ActiveRecord thích DateTime.

Trong các phiên bản trước Ruby 1.9 và trên nhiều hệ thống Thời gian được biểu diễn dưới dạng giá trị được ký 32 bit mô tả số giây kể từ ngày 1 tháng 1 năm 1970 UTC, bao bọc mỏng xung quanh giá trị time_t POSIX tiêu chuẩn và bị chặn :

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

Phiên bản mới hơn của Ruby có thể xử lý các giá trị lớn hơn mà không tạo lỗi.

Ngày giờ là phương pháp dựa trên lịch, nơi năm, tháng, ngày, giờ, phút và giây được lưu trữ riêng lẻ. Đây là một cấu trúc Ruby on Rails phục vụ như một trình bao bọc xung quanh các trường DATETIME chuẩn SQL. Chúng chứa các ngày tùy ý và có thể biểu diễn gần như bất kỳ điểm nào trong thời gian vì phạm vi biểu thức thường rất lớn.

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

Vì vậy, việc đảm bảo rằng DateTime có thể xử lý các bài đăng trên blog từ Aristotle.

Khi chọn một, sự khác biệt có phần chủ quan ngay bây giờ. Lịch sử DateTime đã cung cấp các tùy chọn tốt hơn để thao tác nó theo kiểu lịch, nhưng nhiều phương thức trong số này cũng đã được chuyển sang Thời gian, ít nhất là trong môi trường Rails.

+5

Vì vậy nên tôi luôn luôn sử dụng DateTime? –

+4

Nếu bạn đang làm việc với ngày tháng, tôi muốn nói sử dụng DateTime. Thời gian thuận tiện cho việc biểu diễn những thứ như thời gian hiện tại trong ngày hoặc các điểm trong tương lai gần chẳng hạn như 10.minutes.from_now. Cả hai có nhiều điểm chung, mặc dù DateTime được ghi nhận có thể đại diện cho một phạm vi giá trị rộng hơn nhiều. – tadman

+0

> Thời gian thuận tiện để đại diện cho những thứ như thời gian hiện tại trong ngày hoặc các điểm trong tương lai gần chẳng hạn như 10.minutes.from_now. Tại sao Thời gian thuận tiện hơn so với DateTime cho mục đích này? –

42

Tôi nghĩ câu trả lời cho "sự khác biệt" là một trong những câu trả lời không may phổ biến cho câu hỏi này trong thư viện chuẩn của Ruby: hai lớp/lib được tạo ra khác nhau bởi những người khác nhau vào các thời điểm khác nhau. Đó là một trong những hậu quả không may của bản chất cộng đồng về sự tiến hóa của Ruby so với sự phát triển được hoạch định cẩn thận của một cái gì đó như Java. Các nhà phát triển muốn có chức năng mới nhưng không muốn bước vào các API hiện có để họ chỉ tạo một lớp mới - cho người dùng cuối không có lý do rõ ràng nào cho cả hai tồn tại.

Điều này đúng với các thư viện phần mềm nói chung: thường lý do một số mã hoặc API là cách nó hóa ra là lịch sử hơn là logic.

Sự cám dỗ là bắt đầu với DateTime vì nó có vẻ chung chung hơn. Ngày ... và Thời gian, phải không? Sai rồi. Thời gian cũng có ngày tốt hơn, và trên thực tế có thể phân tích các múi giờ trong đó DateTime không thể. Ngoài ra nó hoạt động tốt hơn.

Tôi đã sử dụng Thời gian ở mọi nơi.

Để an toàn, tôi có xu hướng cho phép đối số DateTime được chuyển vào API thời gian của tôi và chuyển đổi. Ngoài ra nếu tôi biết rằng cả hai đều có phương pháp Tôi quan tâm đến tôi chấp nhận một trong hai, giống như phương pháp này tôi đã viết cho lần chuyển đổi sang XML (cho các tập tin 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 
+8

Ngoài ra, Time.new và DateTime.new đang xử lý múi giờ khác nhau. Tôi đang trên GMT + 7, do đó, 'Thời gian.mới (2011, 11, 1, 10, 30) 'tạo' 2011-11-01 10:30:00 + 0700' trong khi 'DateTime.new (2011, 11, 1, 10, 30)' tạo 'Tue, 01 Tháng 11 năm 2011 10:30:00 + 0000'. –

+19

Và như chúng ta đã biết, việc phát triển Java được lập kế hoạch cẩn thận dẫn đến các API logic đơn giản, độc đáo. – pje

+0

@ PhươngNguyễn: Bạn có thể thêm câu trả lời đó làm câu trả lời để tôi có thể bỏ phiếu không? Đó chính xác là lý do tôi quyết định chọn Time over DateTime. – Senseful

66

lỗi thời! Xem bên dưới ...

Sự khác biệt hiệu suất không thể được nhấn mạnh đủ ...Thời gian là C, và DateTime là Ruby:

>> Benchmark.bm do |bm| 
?> bm.report('DateTime:') do 
?>  n1 = DateTime.now 
>>  n2 = DateTime.now 
>>  1_000_000.times{ n1 < n2 } 
>> end 
>> bm.report('Time: ') do 
?>  n1 = Time.now 
>>  n2 = Time.now 
>>  1_000_000.times{ n1 < n2 } 
>> end 
>> end 
     user  system  total  real 
DateTime: 4.980000 0.020000 5.000000 ( 5.063963) 
Time:  0.330000 0.000000 0.330000 ( 0.335913) 

Cập nhật (2/2012):

Như đã đề cập trong các bình luận, 1.9.3 đã cải thiện đáng kể hiệu suất DateTime:

 user  system  total  real 
DateTime: 0.330000 0.000000 0.330000 ( 0.333869) 
Time:  0.300000 0.000000 0.300000 ( 0.306444) 
+23

: Ruby 1.9.3 sẽ mang lại 'DateTime' nhanh hơn được triển khai trong C: http://www.rubyinside.com/ruby-1-9-3-preview-1-released-5229.html vì vậy câu trả lời này hy vọng có thể không có liên quan lâu hơn nữa. –

+2

Tôi chạy mã của bạn trong ruby ​​2.0.0-p247 và kết quả của tôi là rất khác nhau. Với DateTime nhanh hơn nhiều (5 lần) 'DateTime: 0.520000 0.010000 0.530000 (0.522596) | Thời gian: 2,800000 0,000000 2,800000 (2,814311) ' – Leito

+0

i rean giống nhau trên 32-bit ruby ​​2.0.0p247' DateTime: 0.200000 0.010000 0.210000 (0.200798) | Thời gian: 0.180000 0.000000 0.180000 (0.184122) ' – Kokizzu

9

Tôi đã tìm thấy những thứ như phân tích cú pháp và tính toán đầu/cuối của một ngày trong các múi giờ khác nhau dễ dàng hơn với DateTime, giả sử bạn đang sử dụng các tiện ích ActiveSupport.

Trong trường hợp của tôi, tôi cần tính toán kết thúc trong ngày theo múi giờ của người dùng (tùy ý) dựa trên thời gian địa phương của người dùng mà tôi nhận được dưới dạng chuỗi, ví dụ: "2012/10/10 10:10 0300"

Với DateTime nó đơn giản như

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 

Bây giờ chúng ta hãy thử nó theo cùng một cách với Thời gian:

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. 

Trên thực tế, nhu cầu Thời gian để biết múi giờ trước khi phân tích cú pháp (cũng lưu ý rằng đó là Time.zone.parse, không phải 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 

S o, trong trường hợp này, nó chắc chắn dễ dàng hơn để đi với DateTime.

+0

Sử dụng tính năng này trong sản xuất, có bất kỳ nhược điểm nào đối với kỹ thuật này không? –

+0

DateTime không tính đến thời gian tiết kiệm ánh sáng ban ngày. Do đó khi tiết kiệm thời gian thay đổi, nó sẽ không hoạt động chính xác. 'DateTime.parse ('2014-03-30 01:00:00 +0100'). End_of_day' tạo' Sun, 30 Mar 2014 23:59:59 + 0100', nhưng 'Time.zone = 'CET'; Time.zone.parse ('2014-03-30 01:00:00'). End_of_day' tạo 'Mặt trời, 30 tháng 3 năm 2014 23:59:59 CEST +02: 00' (CET = + 01: 00, CEST = +02: 00 - thông báo mức chênh lệch đã thay đổi). Nhưng để làm điều này, bạn cần thêm thông tin về múi giờ của người dùng (không chỉ bù đắp mà còn tiết kiệm thời gian được sử dụng). –

+0

Có thể nói rõ ràng, nhưng 'Time.zone.parse' là * rất hữu ích khi phân tích cú pháp thời gian với các vùng khác nhau - nó buộc bạn phải nghĩ về vùng nào bạn nên sử dụng. Đôi khi, Time.find_zone hoạt động tốt hơn. – prusswan

75

Kể từ ruby ​​2.0, hầu hết thông tin nói trên đều lỗi thời.

Cụ thể, Time hiện đã bị ràng buộc thực tế. Nó có thể là nhiều hơn hoặc ít hơn thậm chí 63 bit đi từ Epoch:

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 

Hậu quả chỉ sử dụng các giá trị lớn hơn nên hiệu suất, mà là tốt hơn khi Integer s được sử dụng (so với Bignum s (giá trị bên ngoài của Integer phạm vi) hoặc Rational s (khi nano giây được theo dõi)):

Vì Ruby 1.9.2, Triển khai thời gian sử dụng số nguyên 63 bit, Bignum hoặc Rational. Số nguyên là một số nano giây kể từ Epoch có thể đại diện cho 1823-11-12 đến 2116-02-20. Khi Bignum hoặc Rational được sử dụng (trước năm 1823, sau năm 2116, dưới nano giây), Thời gian hoạt động chậm hơn khi sử dụng số nguyên. (http://www.ruby-doc.org/core-2.1.0/Time.html)

Nói cách khác, theo như tôi hiểu, DateTime không còn bao gồm một phạm vi rộng lớn hơn của giá trị tiềm năng hơn Time.

Bên cạnh đó, hai hạn chế trước đó không được đề cập trong DateTime có lẽ nên được lưu ý:

DateTime không xem xét bất kỳ leapseconds, không theo dõi bất kỳ quy tắc thời gian mùa hè. (http://www.ruby-doc.org/stdlib-2.1.0/libdoc/date/rdoc/Date.html#class-Date-label-DateTime)

Thứ nhất, DateTime không có khái niệm về giây nhuận:

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_i 
=> 1341100823 

Thứ hai, DateTime có hiểu biết rất hạn chế về múi giờ và đặc biệt không có khái niệm về ánh sáng ban ngày tiết kiệm. Nó khá nhiều xử lý múi giờ cũng đơn giản UTC + X offsets:

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> 

này có thể gây rắc rối khi lần được nhập như DST và sau đó chuyển đổi thành một múi giờ phi DST mà không theo dõi các offsets đúng ngoài DateTime chính nó (nhiều hệ điều hành có thể thực sự đã chăm sóc điều này cho bạn).

Nhìn chung, tôi muốn nói rằng ngày nay Time là lựa chọn tốt hơn cho hầu hết các ứng dụng. Cũng cần lưu ý một sự khác biệt quan trọng khi bổ sung: khi bạn thêm một số vào đối tượng Thời gian, nó được tính bằng giây, nhưng khi bạn thêm một số vào một DateTime, nó được tính theo ngày.

4

Hãy xem xét cách họ xử lý các múi giờ khác nhau với sự khởi tạo tùy chỉnh:

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 

Điều này có thể được khôn lanh khi tạo dãy thời gian, vv

+0

Chỉ có vẻ như xảy ra với đồng bằng ruby ​​(tức là không có Rails) – vemv

Các vấn đề liên quan