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?
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.
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
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.
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
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.
...
>> 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.
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.
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.
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")
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)
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")
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.
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