Zde je rubínový skript, který jsem napsal, abych změnil konfiguraci časového pásma na Ubuntu. Spouštím to pomocí jruby (překladač Ruby běžící v JVM).
require 'java'
if ARGV.length == 0
puts "Usage: jruby change_timezone.rb America/Toronto"
exit
end
old_zone = File.read("../../../etc/timezone")
puts old_zone
time1 = Time.now
puts "Current Time:"+time1.localtime.to_s
new_zone = ARGV[0]
open('../../../etc/timezone','w') do |f|
f.puts new_zone.to_s
f.close
end
new_zone = File.read("../../../etc/timezone")
puts new_zone
time2 = Time.now
puts "Updated Time:"+time2.localtime.to_s
Správně změní konfigurační soubor. Výstup skriptu však neodpovídá očekávání.
Předpokládejme, že výchozí hodnota časového pásma je America/Toronto
.
Když spustím příkaz jruby change_timezone.rb Asia/Chongqing
, výstup je:
America/Toronto
Current Time:Thu Jul 07 14:43:23 -0400 2011
Asia/Chongqing
Updated Time:Thu Jul 07 14:43:23 -0400 2011 (My Note: +0800 expected!!!)
Pokračujte příkazem jruby change_timezone.rb Europe/Amsterdam
, skončím s následujícím:
Asia/Chongqing
Current Time:Fri Jul 08 03:18:25 +0800 2011 (My Note: it actually got updated from last run!!!)
Europe/Amsterdam
Updated Time:Fri Jul 08 03:18:25 +0800 2011 (My Note: +0200 expected!!!)
Jdeme dále s jruby change_timezone.rb Europe/Amsterdam
opět dostávám následující:
Europe/Amsterdam
Current Time:Thu Jul 07 21:21:27 +0200 2011
Europe/Amsterdam
Updated Time:Thu Jul 07 21:21:27 +0200 2011
Dokáže někdo zjistit, proč to nefungovalo podle očekávání?
Přijatá odpověď:
To je problém v tom, jak Java určuje časové pásmo v systémech unix.
Specifikace POSIX nespecifikuje, jak určit časové pásmo při TZ
není nastavena proměnná prostředí. V Linux Standard Base o tom nemůžu nic najít.
Knihovna základního systému (GNU libc) používá /etc/localtime
k určení časového pásma. Takže na neembedded Linuxu /etc/localtime
je místo, kde jsou uloženy informace o časovém pásmu a v ideálním případě by příběh končil zde.
(Podívejte se kolem:FreeBSD, NetBSD a OpenBSD používají /etc/localtime
. Solaris a několik dalších používá /etc/TIMEZONE
. Rosetta Stone pro Unix ukazuje, co používají ostatní unixy. Dietlibc (používá se v některých vestavěných systémech Linux) používá /etc/localtime
, zatímco uClibc používá /etc/TZ
(pokud není opraveno).)
Bohužel Java dělá věci jinak. Debian a Ubuntu mají soubor s názvem /etc/timezone
který obsahuje název časového pásma. Tento extra soubor je určen pro balicí systém, takže si pamatuje zeměpisný název jako Europe/Amsterdam
spíše než jen popis časového pásma (posuny v čase a zobrazované názvy CET
, CEST
a CEDT
). To je pro lidi přátelštější a robustnější v případě, že geografické prostředí aktualizuje pravidla časového pásma. Sun (nyní Oracle) Java preferuje /etc/timezone
(nebo /etc/sysconfig/clock
na distribucích založených na Red Hatu) viz chyba #6456628 v /etc/localtime
a OpenJDK a gcj následují.
Řešení je jednoduché:vždy aktualizujte /etc/timezone
a /etc/localtime
spolu. Na Debianu nebo Ubuntu je oficiální metoda změny časového pásma dpkg-reconfigure tzdata
. Chcete-li změnit časové pásmo pouze pro jednu aplikaci, nastavte TZ
proměnná prostředí (tato je přenosná napříč všemi unixovými systémy).