रूबी में डेटाइम और टाइम से / में कनवर्ट करें


132

आप रूबी में डेटाइम और टाइम ऑब्जेक्ट के बीच कैसे परिवर्तित होते हैं?


1
मुझे यकीन नहीं है कि यह एक अलग सवाल होना चाहिए, लेकिन आप दिनांक और समय के बीच कैसे परिवर्तित होते हैं?
एंड्रयू ग्रिम

8
रूबी के आधुनिक संस्करणों के तहत स्वीकृत और उच्चतम श्रेणी के उत्तर अब सटीक नहीं हैं। @TheTinMan द्वारा और नीचे @PatrickMcKenzie द्वारा उत्तर देखें ।
फ्रॉगज़

जवाबों:


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

ध्यान दें कि आपको स्थानीय समय और जीएम / यूटीसी समय के बीच चयन करना है।

उपरोक्त दोनों कोड स्निपेट ओ'रेली के रूबी कुकबुक से लिए गए हैं । उनकी कोड पुन: उपयोग नीति इसकी अनुमति देती है।


5
यह 1.9 पर टूट जाएगा जहां DateTime # sec_fraction एक सेकंड में मिलीसेकंड की संख्या लौटाता है। 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 यह निष्पादन में सबसे कुशल नहीं हो सकता है, लेकिन यह काम करता है, यह संक्षिप्त है, और यह बहुत पठनीय है।
वॉल्ट जोन्स

6
दुर्भाग्य से यह केवल स्थानीय समय के साथ काम करते समय वास्तव में काम करता है। यदि आप किसी अलग समयक्षेत्र के साथ दिनांक समय या समय के साथ प्रारंभ करते हैं, तो पार्स फ़ंक्शन स्थानीय समयक्षेत्र में परिवर्तित हो जाएगा। आप मूल रूप से मूल समयक्षेत्र खो देते हैं।
बर्नार्ड

6
रूबी 1.9.1 के रूप में, DateTime.parse टाइमज़ोन को संरक्षित करता है। (मेरे पास पहले के संस्करणों तक पहुंच नहीं है।) Time.parse टाइमज़ोन को संरक्षित नहीं करता है, क्योंकि यह पोसिक्स-मानक time_t का प्रतिनिधित्व करता है, जो मुझे लगता है कि युगों से पूर्णांक अंतर है। समय के लिए किसी भी रूपांतरण का व्यवहार समान होना चाहिए।
अंशुल

1
आप सही हे। DateTime.parse 1.9.1 में काम करता है लेकिन Time.parse नहीं। किसी भी स्थिति में, यह कम त्रुटि वाला (सुसंगत) है और संभावित रूप से DateTime.new (...) और Time.new (..) का उपयोग करने के लिए तेज़ है। नमूना कोड के लिए मेरा जवाब देखें।
बर्नार्ड

1
हाय @ शानशूल। मैं नहीं बता रहा हूँ कि मैं :-) हूँ। Time.parse () का उपयोग करते समय Timezone की जानकारी नहीं रखी जाती है। यह परीक्षण करना आसान है। ऊपर दिए गए कोड में, बस d = DateTime.now को d = DateTime.new (2010,01,01, 10,00,00, Rational (-2, 24)) से बदलें। tt अब आपके स्थानीय समयक्षेत्र में परिवर्तित तिथि को दिखाएगा। आप अभी भी तिथि अंकगणित और सभी कर सकते हैं लेकिन मूल tz जानकारी खो गई है। यह जानकारी दिनांक के लिए एक संदर्भ है और यह अक्सर महत्वपूर्ण है। यहां देखें: stackoverflow.com/questions/279769/…
बर्नार्ड

63

रूबी पारिस्थितिकी तंत्र की स्थिति के लिए एक अद्यतन के रूप में Date, DateTimeऔर Timeअब विभिन्न वर्गों के बीच कनवर्ट करने के लिए तरीके हैं। रूबी का उपयोग 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 एक डेटटाइम देता है ... 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
जेसी क्लार्क

उफ़। बस एहसास हुआ कि यह रूबी मुद्दे पर एक रूबी नहीं रूबी मुद्दा है: stackoverflow.com/questions/11277454/… । यहां तक ​​कि उन्होंने 2.x लाइन में इस पद्धति के खिलाफ एक बग दर्ज किया था और इसे "ठीक नहीं होगा" चिह्नित किया था। भयानक निर्णय IMHO। रेल व्यवहार पूरी तरह से अंतर्निहित रूबी इंटरफ़ेस को तोड़ देता है।
जेसी क्लार्क

12

दुर्भाग्य से, DateTime.to_time, Time.to_datetimeऔर Time.parseफ़ंक्शन टाइमज़ोन जानकारी को बनाए नहीं रखते हैं। रूपांतरण के दौरान सब कुछ स्थानीय समयक्षेत्र में बदल जाता है। तिथि अंकगणित अभी भी काम करते हैं, लेकिन आप उनके मूल टाइमज़ोन के साथ दिनांक प्रदर्शित नहीं कर पाएंगे। वह संदर्भ जानकारी अक्सर महत्वपूर्ण होती है। उदाहरण के लिए, यदि मैं न्यूयॉर्क में व्यावसायिक घंटों के दौरान किए गए लेन-देन को देखना चाहता हूं, तो शायद मैं उन्हें अपने मूल टाइमज़ोन में प्रदर्शित करना पसंद करता हूं, न कि ऑस्ट्रेलिया में मेरे स्थानीय समयक्षेत्र (जो कि न्यूयॉर्क से 12 घंटे आगे है) में।

नीचे दिए गए रूपांतरण तरीके उस tz जानकारी को रखते हैं।

रूबी 1.8 के लिए, गॉर्डन विल्सन के जवाब को देखें । यह अच्छे पुराने विश्वसनीय रूबी कुकबुक से है।

रूबी 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

Timezone सहित पूरी मूल DateTime जानकारी रखी गई है।


2
समय जटिल है, लेकिन विभिन्न अंतर्निहित समय वर्गों के बीच अंतर्निहित रूपांतरण प्रदान नहीं करने का कोई बहाना नहीं है। यदि आप 4713 ईसा पूर्व के लिए UNIX time_t प्राप्त करने का प्रयास करते हैं, तो रेंज रेंज अपवाद को फेंक सकते हैं (हालांकि एक BigNum नकारात्मक मान अच्छा होगा), लेकिन कम से कम इसके लिए एक विधि प्रदान करें।
मार्क रीड

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 को अनदेखा करता है। समय इसका सम्मान करता है, लेकिन केवल "स्थानीय" (सिस्टम वातावरण) में।
एंड्रयू विट

1

गॉर्डन विल्सन समाधान में सुधार, यहाँ मेरी कोशिश है:

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

इस तरह के रूपांतरण करते समय एक वस्तु से दूसरी वस्तु में परिवर्तित होते समय टाइमजोन के व्यवहार को ध्यान में रखना चाहिए। मुझे इस स्टैकओवरफ़्लो पोस्ट में कुछ अच्छे नोट्स और उदाहरण मिले ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.