1

Here is a ruby script I wrote to change the timezone configuration on Ubuntu. I run it with jruby (a Ruby interpreter running in a 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

It does change the configuration file properly. However, the output for the script is not as expected.

Assume the default value for the timezone is America/Toronto. When I run the command jruby change_timezone.rb Asia/Chongqing, the output is:

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!!!)

Continuing with the command jruby change_timezone.rb Europe/Amsterdam, I end up with the following:

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!!!)

Going further with jruby change_timezone.rb Europe/Amsterdam again, I get the following:

Europe/Amsterdam
Current Time:Thu Jul 07 21:21:27 +0200 2011
Europe/Amsterdam
Updated Time:Thu Jul 07 21:21:27 +0200 2011

Can someone figure out why it didn't work as expected?

7
  • Just a note: why are you using relative paths?
    – pbm
    Commented Jul 7, 2011 at 20:02
  • @pbm Good point. Absolute paths can make code more portable. Thanks a lot!
    – Terry Li
    Commented Jul 7, 2011 at 20:21
  • @Gilles As you can see from the output, the time did change while I didn't touch /etc/localtime. What confuses me here is that the time change wouldn't show upon the first run(it showed on the following run!!).
    – Terry Li
    Commented Jul 7, 2011 at 20:27
  • @TerryLee The process reads the timezone the first time it needs it, and doesn't check for changes afterwards. What surprises me is that you're seeing a change without modifying /etc/localtime. Do you see the same effect with plain ruby? Please post the output of ls -l /etc/localtime and strace -efile jruby change_timezone.rb Asia/Chongqing. Commented Jul 7, 2011 at 20:57
  • @Gilles It seems that /etc/localtime won't change between runs. Plus, with plain Ruby I'm not able to see the change. I figure that Time.now results in different objects(java Time vs ruby Time) with jruby vs plain ruby.
    – Terry Li
    Commented Jul 8, 2011 at 13:40

1 Answer 1

7

This is an issue in how Java determines the time zone under unix systems.

The POSIX specification does not specify how to determine the timezone when the TZ environment variable is not set. I can't find anything in the Linux Standard Base about this. The base system library (GNU libc) uses /etc/localtime to determine the timezone. So on non-embedded Linux, /etc/localtime is where the timezone information is stored, and ideally the story would end here.

(Looking around: FreeBSD, NetBSD and OpenBSD use /etc/localtime. Solaris and a few others use /etc/TIMEZONE. The Rosetta Stone for Unix shows what other unices use. Dietlibc (used in some embedded Linux systems) uses /etc/localtime, while uClibc uses /etc/TZ (unless patched).)

Unfortunately, Java does things differently. Debian and Ubuntu have a file called /etc/timezone which contains the name of the timezone. This extra file is intended for the packaging system, so that it remembers a geographical name like Europe/Amsterdam rather than just the description of the timezone (offsets over time, and display names CET, CEST and CEDT). This is both friendlier to humans and robust in case the geographical locale updates its time zone rules. Sun (now Oracle) Java prefers /etc/timezone (or /etc/sysconfig/clock on Red Hat-based distributions) see bug #6456628 to /etc/localtime, and OpenJDK and gcj follow suit.

See also: How do I find the current system timezone?; Java Time Zone is messed up.

The solution is simple: always update /etc/timezone and /etc/localtime together. On Debian or Ubuntu, the official method to change the timezone is dpkg-reconfigure tzdata. To change the timezone only for one application, set the TZ environment variable (this is portable across all unix systems).

1
  • This works. All I needed to do was running sudo dpkg-reconfigure tzdata. After restarting the Java server it picked up the correct timezone. According to this guide, you should also run sudo apt-get install ntp to enable NTP Synchronization. Commented Jul 11, 2015 at 10:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .