Home » openjdk-7 » java » util » [javadoc | source]

    1   /* java.util.VMTimeZone
    2      Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
    3      Free Software Foundation, Inc.
    4   
    5   This file is part of GNU Classpath.
    6   
    7   GNU Classpath is free software; you can redistribute it and/or modify
    8   it under the terms of the GNU General Public License as published by
    9   the Free Software Foundation; either version 2, or (at your option)
   10   any later version.
   11   
   12   GNU Classpath is distributed in the hope that it will be useful, but
   13   WITHOUT ANY WARRANTY; without even the implied warranty of
   14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15   General Public License for more details.
   16   
   17   You should have received a copy of the GNU General Public License
   18   along with GNU Classpath; see the file COPYING.  If not, write to the
   19   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   20   02110-1301 USA.
   21   
   22   Linking this library statically or dynamically with other modules is
   23   making a combined work based on this library.  Thus, the terms and
   24   conditions of the GNU General Public License cover the whole
   25   combination.
   26   
   27   As a special exception, the copyright holders of this library give you
   28   permission to link this library with independent modules to produce an
   29   executable, regardless of the license terms of these independent
   30   modules, and to copy and distribute the resulting executable under
   31   terms of your choice, provided that you also meet, for each linked
   32   independent module, the terms and conditions of the license of that
   33   module.  An independent module is a module which is not derived from
   34   or based on this library.  If you modify this library, you may extend
   35   this exception to your version of the library, but you are not
   36   obligated to do so.  If you do not wish to do so, delete this
   37   exception statement from your version. */
   38   
   39   
   40   package java.util;
   41   
   42   import gnu.classpath.Configuration;
   43   
   44   import java.io;
   45   
   46   /**
   47    *
   48    */
   49   final class VMTimeZone
   50   {
   51     static
   52     {
   53       if (Configuration.INIT_LOAD_LIBRARY)
   54         {
   55   	System.loadLibrary("javautil");
   56         }
   57     }
   58   		
   59     /**
   60      * This method returns a time zone id string which is in the form
   61      * (standard zone name) or (standard zone name)(GMT offset) or
   62      * (standard zone name)(GMT offset)(daylight time zone name).  The
   63      * GMT offset can be in seconds, or where it is evenly divisible by
   64      * 3600, then it can be in hours.  The offset must be the time to
   65      * add to the local time to get GMT.  If a offset is given and the
   66      * time zone observes daylight saving then the (daylight time zone
   67      * name) must also be given (otherwise it is assumed the time zone
   68      * does not observe any daylight savings).
   69      * <p>
   70      * The result of this method is given to the method
   71      * TimeZone.getDefaultTimeZone(String) which tries to map the time
   72      * zone id to a known TimeZone.  See that method on how the returned
   73      * String is mapped to a real TimeZone object.
   74      * <p>
   75      * The reference implementation which is made for GNU/Posix like
   76      * systems calls <code>System.getenv("TZ")</code>,
   77      * <code>readTimeZoneFile("/etc/timezone")</code>,
   78      * <code>readtzFile("/etc/localtime")</code> and finally
   79      * <code>getSystemTimeZoneId()</code> till a supported TimeZone is
   80      * found through <code>TimeZone.getDefaultTimeZone(String)</code>.
   81      * If every method fails <code>null</code> is returned (which means
   82      * the TimeZone code will fall back on GMT as default time zone).
   83      * <p>
   84      * Note that this method is called inside a
   85      * <code>AccessController.doPrivileged()</code> block and runs with
   86      * the priviliges of the java.util system classes.  It will only be
   87      * called when the default time zone is not yet set, the system
   88      * property user.timezone isn't set and it is requested for the
   89      * first time.
   90      */
   91     static TimeZone getDefaultTimeZoneId()
   92     {
   93       TimeZone zone = null;
   94   
   95       // See if TZ environment variable is set and accessible.
   96       String tzid = System.getenv("TZ");
   97       if (tzid != null && !tzid.equals(""))
   98         zone = TimeZone.getDefaultTimeZone(tzid);
   99   
  100       // Try to parse /etc/timezone.
  101       if (zone == null)
  102         {
  103   	tzid = readTimeZoneFile("/etc/timezone");
  104   	if (tzid != null && !tzid.equals(""))
  105   	  zone = TimeZone.getDefaultTimeZone(tzid);
  106         }
  107       
  108       // Try to parse /etc/localtime
  109       if (zone == null)
  110         {
  111   	tzid = readtzFile("/etc/localtime");
  112   	if (tzid != null && !tzid.equals(""))
  113   	  zone = TimeZone.getDefaultTimeZone(tzid);
  114         }
  115   
  116       // Try some system specific way
  117       if (zone == null)
  118         {
  119   	tzid = getSystemTimeZoneId();
  120   	if (tzid != null && !tzid.equals(""))
  121   	  zone = TimeZone.getDefaultTimeZone(tzid);
  122         }
  123   
  124       return zone;
  125     }
  126   
  127     /**
  128      * Tries to read the time zone name from a file. Only the first
  129      * consecutive letters, digits, slashes, dashes and underscores are
  130      * read from the file. If the file cannot be read or an IOException
  131      * occurs null is returned.
  132      * <p>
  133      * The /etc/timezone file is not standard, but a lot of systems have
  134      * it. If it exist the first line always contains a string
  135      * describing the timezone of the host of domain. Some systems
  136      * contain a /etc/TIMEZONE file which is used to set the TZ
  137      * environment variable (which is checked before /etc/timezone is
  138      * read).
  139      */
  140     private static String readTimeZoneFile(String file)
  141     {
  142       File f = new File(file);
  143       if (!f.exists())
  144         return null;
  145   
  146       InputStreamReader isr = null;
  147       try
  148         {
  149   	FileInputStream fis = new FileInputStream(f);
  150   	BufferedInputStream bis = new BufferedInputStream(fis);
  151   	isr = new InputStreamReader(bis);
  152   	
  153   	StringBuffer sb = new StringBuffer();
  154   	int i = isr.read();
  155   	while (i != -1)
  156   	  {
  157   	    char c = (char) i;
  158   	    if (Character.isLetter(c) || Character.isDigit(c)
  159   		|| c == '/' || c == '-' || c == '_')
  160   	      {
  161   		sb.append(c);
  162   		i = isr.read();
  163   	      }
  164   	    else
  165   	      break;
  166   	  }
  167   	return sb.toString();
  168         }
  169       catch (IOException ioe)
  170         {
  171   	// Parse error, not a proper tzfile.
  172   	return null;
  173         }
  174       finally
  175         {
  176   	try
  177   	  {
  178   	    if (isr != null)
  179   	      isr.close();
  180   	  }
  181   	catch (IOException ioe)
  182   	  {
  183   	    // Error while close, nothing we can do.
  184   	  }
  185         }
  186     }
  187   
  188     /**
  189      * Tries to read a file as a "standard" tzfile and return a time
  190      * zone id string as expected by <code>getDefaultTimeZone(String)</code>.
  191      * If the file doesn't exist, an IOException occurs or it isn't a tzfile
  192      * that can be parsed null is returned.
  193      * <p>
  194      * The tzfile structure (as also used by glibc) is described in the Olson
  195      * tz database archive as can be found at
  196      * <code>ftp://elsie.nci.nih.gov/pub/</code>.
  197      * <p>
  198      * At least the following platforms support the tzdata file format
  199      * and /etc/localtime (GNU/Linux, Darwin, Solaris and FreeBSD at
  200      * least). Some systems (like Darwin) don't start the file with the
  201      * required magic bytes 'TZif', this implementation can handle
  202      * that).
  203      */
  204     private static String readtzFile(String file)
  205     {
  206       File f = new File(file);
  207       if (!f.exists())
  208         return null;
  209       
  210       DataInputStream dis = null;
  211       try
  212         {
  213           FileInputStream fis = new FileInputStream(f);
  214           BufferedInputStream bis = new BufferedInputStream(fis);
  215           dis = new DataInputStream(bis);
  216   	
  217           // Make sure we are reading a tzfile.
  218           byte[] tzif = new byte[4];
  219           dis.readFully(tzif);
  220           if (tzif[0] == 'T' && tzif[1] == 'Z'
  221               && tzif[2] == 'i' && tzif[3] == 'f')
  222   	  // Reserved bytes, ttisgmtcnt, ttisstdcnt and leapcnt
  223   	  skipFully(dis, 16 + 3 * 4);
  224   	else
  225   	  // Darwin has tzdata files that don't start with the TZif marker
  226   	  skipFully(dis, 16 + 3 * 4 - 4);
  227   	
  228   	int timecnt = dis.readInt();
  229   	int typecnt = dis.readInt();
  230   	if (typecnt > 0)
  231   	  {
  232   	    int charcnt = dis.readInt();
  233   	    // Transition times plus indexed transition times.
  234   	    skipFully(dis, timecnt * (4 + 1));
  235   	    
  236   	    // Get last gmt_offset and dst/non-dst time zone names.
  237   	    int abbrind = -1;
  238   	    int dst_abbrind = -1;
  239   	    int gmt_offset = 0;
  240   	    while (typecnt-- > 0)
  241   	      {
  242   		// gmtoff
  243   		int offset = dis.readInt();
  244   		int dst = dis.readByte();
  245   		if (dst == 0)
  246   		  {
  247   		    abbrind = dis.readByte();
  248   		    gmt_offset = offset;
  249   		  }
  250   		else
  251   		  dst_abbrind = dis.readByte();
  252   	      }
  253   	    
  254   	    // gmt_offset is the offset you must add to UTC/GMT to
  255   	    // get the local time, we need the offset to add to
  256   	    // the local time to get UTC/GMT.
  257   	    gmt_offset *= -1;
  258   	    
  259   	    // Turn into hours if possible.
  260   	    if (gmt_offset % 3600 == 0)
  261   	      gmt_offset /= 3600;
  262   	    
  263   	    if (abbrind >= 0)
  264   	      {
  265   		byte[] names = new byte[charcnt];
  266   		dis.readFully(names);
  267   		int j = abbrind;
  268   		while (j < charcnt && names[j] != 0)
  269   		  j++;
  270   		
  271   		String zonename = new String(names, abbrind, j - abbrind,
  272   					     "ASCII");
  273   		
  274   		String dst_zonename;
  275   		if (dst_abbrind >= 0)
  276   		  {
  277   		    j = dst_abbrind;
  278   		    while (j < charcnt && names[j] != 0)
  279   		      j++;
  280   		    dst_zonename = new String(names, dst_abbrind,
  281   					      j - dst_abbrind, "ASCII");
  282   		  }
  283   		else
  284   		  dst_zonename = "";
  285   		
  286   		// Only use gmt offset when necessary.
  287   		// Also special case GMT+/- timezones.
  288   		String offset_string;
  289   		if ("".equals(dst_zonename)
  290   		    && (gmt_offset == 0
  291   			|| zonename.startsWith("GMT+")
  292   			|| zonename.startsWith("GMT-")))
  293   		  offset_string = "";
  294   		else
  295   		  offset_string = Integer.toString(gmt_offset);
  296   		
  297   		String id = zonename + offset_string + dst_zonename;
  298   		
  299   		return id;
  300   	      }
  301   	  }
  302   	
  303   	// Something didn't match while reading the file.
  304   	return null;
  305         }
  306       catch (IOException ioe)
  307         {
  308   	// Parse error, not a proper tzfile.
  309   	return null;
  310         }
  311       finally
  312         {
  313   	try
  314   	  {
  315   	    if (dis != null)
  316   	      dis.close();
  317   	  }
  318   	catch(IOException ioe)
  319   	  {
  320   	    // Error while close, nothing we can do.
  321   	  }
  322         }
  323     }
  324     
  325     /**
  326      * Skips the requested number of bytes in the given InputStream.
  327      * Throws EOFException if not enough bytes could be skipped.
  328      * Negative numbers of bytes to skip are ignored.
  329      */
  330     private static void skipFully(InputStream is, long l) throws IOException
  331     {
  332       while (l > 0)
  333         {
  334           long k = is.skip(l);
  335           if (k <= 0)
  336             throw new EOFException();
  337           l -= k;
  338         }
  339     }
  340   
  341     /**
  342      * Tries to get the system time zone id through native code.
  343      */
  344     private static native String getSystemTimeZoneId();
  345   }

Home » openjdk-7 » java » util » [javadoc | source]