blob: 5724180d71910f34af67f4274add454fc8818d9e [file] [log] [blame]
Raymes Khouryb08a68f2011-10-05 00:05:311/* java.util.VMTimeZone
Han Shenb42cc222013-11-18 20:49:222 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2007, 2010
Raymes Khouryb08a68f2011-10-05 00:05:313 Free Software Foundation, Inc.
4
5This file is part of GNU Classpath.
6
7GNU Classpath is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU Classpath is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Classpath; see the file COPYING. If not, write to the
19Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
2002110-1301 USA.
21
22Linking this library statically or dynamically with other modules is
23making a combined work based on this library. Thus, the terms and
24conditions of the GNU General Public License cover the whole
25combination.
26
27As a special exception, the copyright holders of this library give you
28permission to link this library with independent modules to produce an
29executable, regardless of the license terms of these independent
30modules, and to copy and distribute the resulting executable under
31terms of your choice, provided that you also meet, for each linked
32independent module, the terms and conditions of the license of that
33module. An independent module is a module which is not derived from
34or based on this library. If you modify this library, you may extend
35this exception to your version of the library, but you are not
36obligated to do so. If you do not wish to do so, delete this
37exception statement from your version. */
38
39
40package java.util;
41
42import gnu.classpath.Configuration;
43import gnu.classpath.SystemProperties;
44import gnu.java.util.ZoneInfo;
45import java.util.TimeZone;
46
47import java.io.*;
48
49/**
50 *
51 */
52final class VMTimeZone
53{
Han Shenb42cc222013-11-18 20:49:2254
Raymes Khouryb08a68f2011-10-05 00:05:3155 static
56 {
57 if (Configuration.INIT_LOAD_LIBRARY)
58 {
59 System.loadLibrary("javautil");
60 }
61 }
62
Han Shenb42cc222013-11-18 20:49:2263 private VMTimeZone() {} // Prohibits instantiation.
64
Raymes Khouryb08a68f2011-10-05 00:05:3165 /**
66 * This method returns a time zone id string which is in the form
67 * (standard zone name) or (standard zone name)(GMT offset) or
68 * (standard zone name)(GMT offset)(daylight time zone name). The
69 * GMT offset can be in seconds, or where it is evenly divisible by
70 * 3600, then it can be in hours. The offset must be the time to
71 * add to the local time to get GMT. If a offset is given and the
72 * time zone observes daylight saving then the (daylight time zone
73 * name) must also be given (otherwise it is assumed the time zone
74 * does not observe any daylight savings).
75 * <p>
76 * The result of this method is given to the method
77 * TimeZone.getDefaultTimeZone(String) which tries to map the time
78 * zone id to a known TimeZone. See that method on how the returned
79 * String is mapped to a real TimeZone object.
80 * <p>
81 * The reference implementation which is made for GNU/Posix like
82 * systems calls <code>System.getenv("TZ")</code>,
83 * <code>readTimeZoneFile("/etc/timezone")</code>,
84 * <code>ZoneInfo.readTZFile((String)null, "/etc/localtime")</code>
85 * and finally <code>getSystemTimeZoneId()</code> till a supported
86 * TimeZone is found through
87 * <code>TimeZone.getDefaultTimeZone(String)</code>.
88 * If every method fails <code>null</code> is returned (which means
89 * the TimeZone code will fall back on GMT as default time zone).
90 * <p>
91 * Note that this method is called inside a
92 * <code>AccessController.doPrivileged()</code> block and runs with
93 * the priviliges of the java.util system classes. It will only be
94 * called when the default time zone is not yet set, the system
95 * property user.timezone isn't set and it is requested for the
96 * first time.
97 */
98 static TimeZone getDefaultTimeZoneId()
99 {
100 TimeZone zone = null;
101
102 // See if TZ environment variable is set and accessible.
103 String tzid = System.getenv("TZ");
104 if (tzid != null && !tzid.equals(""))
105 zone = TimeZone.getDefaultTimeZone(tzid);
106
107 // Try to parse /etc/timezone.
108 if (zone == null)
109 {
110 tzid = readTimeZoneFile("/etc/timezone");
111 if (tzid != null && !tzid.equals(""))
112 zone = TimeZone.getDefaultTimeZone(tzid);
113 }
114
115 // Try to parse /etc/localtime
116 if (zone == null)
117 {
118 zone = ZoneInfo.readTZFile((String) null, "/etc/localtime");
119 if (zone != null)
120 {
121 // Try to find a more suitable ID for the /etc/localtime
122 // timezone.
123 // Sometimes /etc/localtime is a symlink to some
124 // /usr/share/zoneinfo/ file.
125 String id = null;
126 try
127 {
128 id = new File("/etc/localtime").getCanonicalPath();
129 if (id != null)
130 {
131 String zoneinfo_dir
132 = SystemProperties.getProperty("gnu.java.util.zoneinfo.dir");
133 if (zoneinfo_dir != null)
134 zoneinfo_dir
135 = new File(zoneinfo_dir
136 + File.separatorChar).getCanonicalPath();
137 if (zoneinfo_dir != null && id.startsWith(zoneinfo_dir))
138 {
139 int pos = zoneinfo_dir.length();
140 while (pos < id.length()
141 && id.charAt(pos) == File.separatorChar)
142 pos++;
143 if (pos < id.length())
144 id = id.substring(pos);
145 else
146 id = null;
147 }
148 else
149 id = null;
150 }
151 }
152 catch (IOException ioe)
153 {
154 id = null;
155 }
156
157 if (id == null)
158 id = readSysconfigClockFile("/etc/sysconfig/clock");
159
160 if (id != null)
161 zone.setID(id);
162 }
163 }
164
165 // Try some system specific way
166 if (zone == null)
167 {
168 tzid = getSystemTimeZoneId();
169 if (tzid != null && !tzid.equals(""))
170 zone = TimeZone.getDefaultTimeZone(tzid);
171 }
172
173 return zone;
174 }
175
176 /**
177 * Tries to read the time zone name from a file. Only the first
178 * consecutive letters, digits, slashes, dashes and underscores are
179 * read from the file. If the file cannot be read or an IOException
180 * occurs null is returned.
181 * <p>
182 * The /etc/timezone file is not standard, but a lot of systems have
183 * it. If it exist the first line always contains a string
184 * describing the timezone of the host of domain. Some systems
185 * contain a /etc/TIMEZONE file which is used to set the TZ
186 * environment variable (which is checked before /etc/timezone is
187 * read).
188 */
189 private static String readTimeZoneFile(String file)
190 {
191 File f = new File(file);
192 if (!f.exists())
193 return null;
194
195 InputStreamReader isr = null;
196 try
197 {
198 FileInputStream fis = new FileInputStream(f);
199 BufferedInputStream bis = new BufferedInputStream(fis);
200 isr = new InputStreamReader(bis);
201
202 StringBuffer sb = new StringBuffer();
203 int i = isr.read();
204 while (i != -1)
205 {
206 char c = (char) i;
207 if (Character.isLetter(c) || Character.isDigit(c)
208 || c == '/' || c == '-' || c == '_')
209 {
210 sb.append(c);
211 i = isr.read();
212 }
213 else
214 break;
215 }
216 return sb.toString();
217 }
218 catch (IOException ioe)
219 {
220 // Parse error, not a proper tzfile.
221 return null;
222 }
223 finally
224 {
225 try
226 {
227 if (isr != null)
228 isr.close();
229 }
230 catch (IOException ioe)
231 {
232 // Error while close, nothing we can do.
233 }
234 }
235 }
236
237 /**
238 * Tries to read the time zone name from a file.
239 * If the file cannot be read or an IOException occurs null is returned.
240 * <p>
241 * The /etc/sysconfig/clock file is not standard, but a lot of systems
242 * have it. The file is included by shell scripts and the timezone
243 * name is defined in ZONE variable.
244 * This routine should grok it with or without quotes:
245 * ZONE=America/New_York
246 * or
247 * ZONE="Europe/London"
248 */
249 private static String readSysconfigClockFile(String file)
250 {
251 BufferedReader br = null;
252 try
253 {
254 FileInputStream fis = new FileInputStream(file);
255 BufferedInputStream bis = new BufferedInputStream(fis);
256 br = new BufferedReader(new InputStreamReader(bis));
257
258 for (String line = br.readLine(); line != null; line = br.readLine())
259 {
260 line = line.trim();
261 if (line.length() < 8 || !line.startsWith("ZONE="))
262 continue;
263 int posstart = 6;
264 int posend;
265 if (line.charAt(5) == '"')
266 posend = line.indexOf('"', 6);
267 else if (line.charAt(5) == '\'')
268 posend = line.indexOf('\'', 6);
269 else
270 {
271 posstart = 5;
272 posend = line.length();
273 }
274 if (posend < 0)
275 return null;
276 return line.substring(posstart, posend);
277 }
278 return null;
279 }
280 catch (IOException ioe)
281 {
282 // Parse error, not a proper tzfile.
283 return null;
284 }
285 finally
286 {
287 try
288 {
289 if (br != null)
290 br.close();
291 }
292 catch (IOException ioe)
293 {
294 // Error while close, nothing we can do.
295 }
296 }
297 }
298
299 /**
300 * Tries to get the system time zone id through native code.
301 */
302 private static native String getSystemTimeZoneId();
303}