แปลงเวลาจากโซนเวลาหนึ่งไปเป็นอีกโซนใน Rails


105

การcreated_atประทับเวลาของฉันถูกเก็บไว้ใน UTC:

>> Annotation.last.created_at
=> Sat, 29 Aug 2009 23:30:09 UTC +00:00

ฉันจะแปลงหนึ่งในนั้นเป็น 'เวลาตะวันออก (สหรัฐอเมริกาและแคนาดา)' (โดยคำนึงถึงการออมแสง) สิ่งที่ต้องการ:

Annotation.last.created_at.in_eastern_time

คำตอบ:


191

ใช้เมธอด in_time_zone ของคลาส DateTime

Loading development environment (Rails 2.3.2)
>> now = DateTime.now.utc
=> Sun, 06 Sep 2009 22:27:45 +0000
>> now.in_time_zone('Eastern Time (US & Canada)')
=> Sun, 06 Sep 2009 18:27:45 EDT -04:00
>> quit

ดังนั้นสำหรับตัวอย่างเฉพาะของคุณ

Annotation.last.created_at.in_time_zone('Eastern Time (US & Canada)')

7
หรือคุณสามารถใช้รหัสชั่วโมงnow.in_time_zone(3)
fl00r

8
created_at.in_time_zone("EST")สั้นกว่า
ออร์แลนโด

51
"EST" = "เวลามาตรฐานตะวันออก" ดังนั้นจะผิดในระหว่างเวลาออมแสง "เวลาตะวันออก (สหรัฐอเมริกาและแคนาดา)" จะระบุว่าเป็นเวลา DST หรือไม่สำหรับคุณ
jhiro009

1
โปรดทราบว่าเมธอด in_time_zone เป็นส่วนหนึ่งของ ActiveSupport ดังนั้นจึงถูกสร้างไว้ใน Rails แต่ไม่ได้เป็นส่วนหนึ่งของ Ruby stdlib หากคุณมีแอปรางก็ไม่มีปัญหา หากคุณมีแอป Ruby ตรงคุณจะต้องแน่ใจว่าต้องการการสนับสนุนที่ใช้งานอยู่
Gayle

ลิงก์ไปยังเอกสารสำหรับวิธีนี้อยู่ที่นี่: apidock.com/rails/DateTime/in_time_zone
Naved Khan

17

แม้ว่านี่จะเป็นคำถามเก่า แต่ก็ควรค่าแก่การกล่าวถึงบางสิ่ง ในการตอบกลับก่อนหน้านี้แนะนำให้ใช้ before_filter เพื่อตั้งค่าเขตเวลาชั่วคราว

คุณไม่ควรทำเช่นนั้นเพราะ Time.zone เก็บข้อมูลในเธรดและอาจรั่วไหลไปยังคำขอถัดไปที่จัดการโดยเธรดนั้น

แต่คุณควรใช้ around_filter เพื่อให้แน่ใจว่า Time.zone ถูกรีเซ็ตหลังจากการร้องขอเสร็จสมบูรณ์ สิ่งที่ต้องการ:

around_filter :set_time_zone

private

def set_time_zone
  old_time_zone = Time.zone
  Time.zone = current_user.time_zone if logged_in?
  yield
ensure
  Time.zone = old_time_zone
end

อ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ที่นี่


1
มีวิธีTime.use_zone ที่ดีในปัจจุบัน
freemanoid

9

หากคุณเพิ่มสิ่งนี้ลงในไฟล์ /config/application.rb

config.time_zone = 'Eastern Time (US & Canada)'

จากนั้นคุณสามารถเซลล์

Annotation.last.created_at.in_time_zone

เพื่อรับเวลาในเขตเวลาที่ระบุ


หากเรากำลังกำหนดค่าโซนเวลาใน application.rb ก็ไม่จำเป็นต้องเรียก ".in_time_zone" รางทำเพื่อเราโดยอัตโนมัติ jyst ต้องเรียก Annotation.last.created_at
Vishal

3

หากคุณกำหนดค่าไฟล์ /config/application.rb

config.time_zone = 'Eastern Time (US & Canada)'

Time.now.in_time_zone

DateTime.now.in_time_zone

2

ตั้งเขตเวลาของคุณเป็นเวลาตะวันออก

คุณสามารถตั้งค่าเขตเวลาเริ่มต้นของคุณใน config / environment.rb

config.time_zone = "Eastern Time (US & Canada)"

ตอนนี้ระเบียนทั้งหมดที่คุณดึงออกมาจะอยู่ในเขตเวลานั้น หากคุณต้องการเขตเวลาที่แตกต่างกันให้พูดตามเขตเวลาของผู้ใช้คุณสามารถเปลี่ยนได้โดยใช้ before_filter ในตัวควบคุมของคุณ

class ApplicationController < ActionController::Base

  before_filter :set_timezone

  def set_timezone
    Time.zone = current_user.time_zone
  end
end

ตรวจสอบให้แน่ใจว่าคุณจัดเก็บเวลาทั้งหมดของคุณไว้ในฐานข้อมูลเป็น UTC แล้วทุกอย่างจะน่ารัก


สิ่งนี้สำคัญหรือไม่หากคุณกำลังใช้งานแอปพลิเคชันเซิร์ฟเวอร์เช่น mongrel, thin หรือenger? พวกเขารันมากกว่าหนึ่งอินสแตนซ์ฉันเชื่อว่าเธรดเดียว? ฉันอาจจะผิดก็อยากรู้!
nitecoder

4
Time.zone=เป็นด้ายปลอดภัยgithub.com/rails/rails/blob/master/activesupport/lib/...
เกรงว่า

มันอาจจะไม่ได้อยู่ในปี '09?
nitecoder

2
@jpwynn: ตามนี้เลย: github.com/rails/rails/commit/…มัน Thread ปลอดภัยมานานกว่า 5 ปี แหล่งที่มาหรือตัวอย่างสำหรับปัญหาของคุณ?
Pascal

1
เธรดสามารถให้บริการได้หลายเซสชัน คุณจะตั้งค่าหนึ่งครั้งเมื่อผู้ใช้เข้าสู่ระบบตัวอย่างเช่นผู้ใช้ LAST ที่เข้าสู่ระบบจะกำหนดเขตเวลาสำหรับผู้ใช้ทั้งหมดที่เซสชันใช้เธรดเดียวกัน ดังนั้นคุณต้องใช้ before_filter เพื่อตั้งค่าสำหรับผู้ใช้ทุกคนสำหรับการโหลดทุกหน้า
jpw
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.