web-dev-qa-db-fra.com

Comment modifier le décalage de zone pendant un certain temps dans Ruby on Rails?

J'ai une variable foo qui contient une heure, disons à 16 heures aujourd'hui, mais le décalage de zone est incorrect, c'est-à-dire qu'il se situe dans le mauvais fuseau horaire. Comment changer le fuseau horaire?

Quand je l'imprime je reçois

Fri Jun 26 07:00:00 UTC 2009

Donc, il n'y a pas de décalage, et j'aimerais régler le décalage sur -4 ou l'heure normale de l'Est.

Je m'attendrais à pouvoir définir simplement le décalage en tant que propriété de l'objet Time, mais cela ne semble pas être disponible?

24
Janak

J'utilise Rails 2.0 avant l'ajout du code qui permet à la solution weppos de fonctionner. Voici ce que j'ai fait

# Silly hack, because sometimes the input_date is in the wrong timezone
temp = input_date.to_time.to_a
temp[8] = true
temp[9] = "Eastern Daylight Time"
input_date = Time.local(*temp)

Je décompose le temps en un tableau de 10 éléments, change le fuseau horaire, puis reconvertit le tableau en une heure.

2
Janak

Vous ne dites pas explicitement comment vous obtenez la variable réelle, mais puisque vous mentionnez la classe Time, je suppose que vous avez le temps avec cela et que je le mentionnerai dans ma réponse.

Le fuseau horaire fait en fait partie de la classe Time (dans votre cas, le fuseau horaire est affiché au format UTC). Time.now retournera le décalage à partir de UTC dans le cadre de la réponse Time.now.

>> local = Time.now
=> 2012-08-13 08:36:50 +0000
>> local.hour
=> 8
>> local.min
=> 36
>> 


... dans ce cas, je suis dans le même fuseau horaire que GMT

Conversion entre les fuseaux horaires

Le moyen le plus simple que j'ai trouvé est de changer le décalage en utilisant le format '+/- HH: MM' par la méthode getlocal. Imaginons que je veuille me convertir entre le temps passé à Dublin et le temps passé à New York

?> dublin = Time.now
=> 2012-08-13 08:36:50 +0000
>> new_york = dublin + Time.zone_offset('EST')
=> 2012-08-13 08:36:50 +0000
>> dublin.hour
=> 8
>> new_york.hour
=> 3

En supposant que "EST" soit le nom du fuseau horaire de New York, comme le souligne Dan, "EDT" est parfois la bonne TZ.

17
Chris McCauley

Si donné:

2011-10-25 07:21:35 -700

tu veux:

2011-10-25 07:21:35 UTC

alors fais:

Time.parse(Time.now.strftime('%Y-%m-%d %H:%M:%S UTC')).to_s
15
99miles

Cela tire parti du fait que Time#asctime n'inclut pas la zone.

Donné un temps:

>> time = Time.now
=> 2013-03-13 13:01:48 -0500

Le forcer dans une autre zone (cela retourne un ActiveSupport::TimeWithZone):

>> ActiveSupport::TimeZone['US/Pacific'].parse(time.asctime)
=> Wed, 13 Mar 2013 13:01:48 PDT -07:00

Notez que la zone d'origine est complètement ignorée. Si je convertis l'heure d'origine en utc, le résultat sera différent:

>> ActiveSupport::TimeZone['US/Pacific'].parse(time.getutc.asctime)
=> Wed, 13 Mar 2013 18:01:48 PDT -07:00

Vous pouvez utiliser to_time ou to_datetime sur le résultat pour obtenir un Time ou DateTime correspondant.

Cette question utilise une approche intéressante avec DateTime#change pour définir le décalage tz. (Rappelez-vous qu'ActiveSupport facilite la conversion entre Time et DateTime.) L'inconvénient est qu'il n'y a pas de détection DST; vous devez le faire manuellement en utilisant le current_period de TZInfo.

14
Kelvin

...

>> Time.at(Time.now.utc + Time.zone_offset('PST'))
=> Mon Jun 07 22:46:22 UTC 2010
>> Time.at(Time.now.utc + Time.zone_offset('PDT'))
=> Mon Jun 07 23:46:26 UTC 2010
>> Time.at(Time.now.utc + Time.zone_offset('CST'))
=> Tue Jun 08 00:46:32 UTC 2010

Remarque: assurez-vous que l'objet heure actuel est d'abord défini sur l'heure UTC, sinon Ruby essaiera de convertir l'objet Heure en votre fuseau horaire local, ce qui lancera le calcul. Vous pouvez toujours obtenir le temps ajusté en appliquant ".utc" à la fin des instructions ci-dessus dans ce cas.

11
ALW

Pour ceux qui ont découvert cela en cherchant une solution non-Rails (comme je l'ai fait), TZInfo l'a résolu pour moi ...

require 'tzinfo'
def adjust_time time, time_zone="America/Los_Angeles"
    return TZInfo::Timezone.get(time_zone).utc_to_local(time.utc)
end

puts adjust_time(Time.now) 
#=> PST or PDT
puts adjust_time(Time.now, "America/New_York")
#=> EST or EDT

Cela gère également l'heure d'été, qui est ce dont j'avais besoin qui n'a pas été traitée ci-dessus.

Voir: http://tzinfo.rubyforge.org/

10
jmervine

dans votre environnement.rb recherchez la ligne suivante.

# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names.
config.time_zone = 'UTC'

N'oubliez pas qu'ActiveRecord et Rails traitent toujours Time en UTC en interne.

5
Simone Carletti

Voici ce qui a fonctionné pour moi...

def convert_zones(to_zone)
   to_zone_time = to_zone.localtime
end


# have your time set as time

time = convert_zones(time)
time.strftime("%b #{day}, %Y (%a) #{hour}:%M %p %Z")
1
Kris

C’est ce que j’ai fait, car je n’utilise pas Rails et ne souhaite utiliser aucun bijou non essentiel.

t = Time.now # my local time - which is GMT
zone_offset = 3600 # offset for CET - which is my target time zone
zone_offset += 3600 if t.dst? # an extra hour offset in summer
time_cet = Time.mktime(t.sec, t.min, t.hour, t.mday, t.mon, t.year, nil, nil, t.dst?, zone_offset)
0
Chris Kimpton

C'est probablement une bonne idée de stocker l'heure au format UTC, puis de l'afficher dans un fuseau horaire spécifique lors de son affichage. Voici un moyen simple de le faire (fonctionne dans Rails 4, avec des doutes sur les versions précédentes).

t = Time.now.utc

=> 2016-04-19 20:18:33 UTC

t.in_time_zone("EST")

=> Tue, 19 Apr 2016 15:18:33 EST -05:00

Mais si vous voulez vraiment le stocker dans un fuseau horaire spécifique, vous pouvez simplement définir l'objet Time initial sur lui-même.in_time_zone comme ceci:

t = t.in_time_zone("EST")
0
ryan0

Quand analyser une heure

Je serais intéressé de savoir comment vous définissez la variable foo pour commencer.

Si vous analysez une chaîne temporelle qui n'a pas de fuseau horaire (ce que je faisais lors d'une importation de données), vous pouvez utiliser String#in_time_zone pour forcer le fuseau horaire lors de l'analyse:

"Fri Jun 26 2019 07:00:00".in_time_zone( "Eastern Time (US & Canada)" ) 
# => Wed, 26 Jun 2019 07:00:00 EDT -04:00

Fonctionne comme un charme et est super propre.

0
Joshua Pinter

Option 1

Utilisez date_time_attribute gem :

my_date_time = DateTimeAttribute::Container.new(Time.zone.now)
my_date_time.date_time           # => 2001-02-03 22:00:00 KRAT +0700
my_date_time.time_zone = 'Moscow'
my_date_time.date_time           # => 2001-02-03 22:00:00 MSK +0400

Option 2

Si time est utilisé comme attribut, vous pouvez utiliser le même date_time_attribute gem :

class Task
  include DateTimeAttribute
  date_time_attribute :due_at
end

task = Task.new
task.due_at_time_zone = 'Moscow'
task.due_at                      # => Mon, 03 Feb 2013 22:00:00 MSK +04:00
task.due_at_time_zone = 'London'
task.due_at                      # => Mon, 03 Feb 2013 22:00:00 GMT +00:00
0
Sergei Zinin