Import GNU Classpath (20121202).
[official-gcc.git] / libjava / classpath / native / jni / java-util / java_util_VMTimeZone.c
blob0830cbe8cb06e9a7e83df4dfccda927fe3a2684f
1 /* VMTimeZone.c - Native method for java.util.VMTimeZone
2 Copyright (C) 1999, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 #include "config.h"
40 #if TIME_WITH_SYS_TIME
41 # include <sys/time.h>
42 # include <time.h>
43 #else
44 # if HAVE_SYS_TIME_H
45 # include <sys/time.h>
46 # else
47 # include <time.h>
48 # endif
49 #endif
51 #include <stdio.h>
52 #include <string.h>
53 #include <stdlib.h>
55 #include <jni.h>
56 #include <jcl.h>
58 #include "java_util_VMTimeZone.h"
60 static size_t jint_to_charbuf (char *bufend, jint num);
62 /**
63 * This method returns a time zone id string which is in the form
64 * (standard zone name) or (standard zone name)(GMT offset) or
65 * (standard zone name)(GMT offset)(daylight time zone name). The
66 * GMT offset can be in seconds, or where it is evenly divisible by
67 * 3600, then it can be in hours. The offset must be the time to
68 * add to the local time to get GMT. If a offset is given and the
69 * time zone observes daylight saving then the (daylight time zone
70 * name) must also be given (otherwise it is assumed the time zone
71 * does not observe any daylight savings).
72 * <p>
73 * The result of this method is given to getDefaultTimeZone(String)
74 * which tries to map the time zone id to a known TimeZone. See
75 * that method on how the returned String is mapped to a real
76 * TimeZone object.
78 JNIEXPORT jstring JNICALL
79 Java_java_util_VMTimeZone_getSystemTimeZoneId (JNIEnv * env,
80 jclass clazz
81 __attribute__ ((__unused__)))
83 struct tm tim;
84 #ifndef HAVE_LOCALTIME_R
85 struct tm *lt_tim;
86 #endif
87 #ifdef HAVE_TM_ZONE
88 int month;
89 #endif
90 time_t current_time;
91 long tzoffset;
92 const char *tz1, *tz2;
93 char tzoff[11];
94 size_t tz1_len, tz2_len, tzoff_len;
95 char *tzid;
96 jstring retval;
98 time (&current_time);
99 #ifdef HAVE_LOCALTIME_R
100 localtime_r (&current_time, &tim);
101 #else
102 /* Fall back on non-thread safe localtime. */
103 lt_tim = localtime (&current_time);
104 memcpy (&tim, lt_tim, sizeof (struct tm));
105 #endif
106 mktime (&tim);
108 #ifdef HAVE_STRUCT_TM_TM_ZONE
109 /* We will cycle through the months to make sure we hit dst. */
110 month = tim.tm_mon;
111 tz1 = tz2 = NULL;
112 while (tz1 == NULL || tz2 == NULL)
114 if (tim.tm_isdst > 0)
115 tz2 = tim.tm_zone;
116 else if (tz1 == NULL)
118 tz1 = tim.tm_zone;
119 month = tim.tm_mon;
122 if (tz1 == NULL || tz2 == NULL)
124 tim.tm_mon++;
125 tim.tm_mon %= 12;
128 if (tim.tm_mon == month && tz2 == NULL)
129 tz2 = "";
130 else
131 mktime (&tim);
133 /* We want to make sure the tm struct we use later on is not dst. */
134 tim.tm_mon = month;
135 mktime (&tim);
136 #elif defined (HAVE_TZNAME)
137 /* If dst is never used, tzname[1] is the empty string. */
138 tzset ();
139 tz1 = tzname[0];
140 tz2 = tzname[1];
141 #else
142 /* Some targets have no concept of timezones. Assume GMT without dst. */
143 tz1 = "GMT";
144 tz2 = "";
145 #endif
147 #ifdef STRUCT_TM_HAS_GMTOFF
148 /* tm_gmtoff is the number of seconds that you must add to GMT to get
149 local time, we need the number of seconds to add to the local time
150 to get GMT. */
151 tzoffset = -1L * tim.tm_gmtoff;
152 #elif HAVE_UNDERSCORE_TIMEZONE
153 /* On some systems _timezone is actually defined as time_t. */
154 tzoffset = (long) _timezone;
155 #elif HAVE_TIMEZONE
156 /* timezone is secs WEST of UTC. */
157 tzoffset = timezone;
158 #else
159 /* FIXME: there must be another global if neither tm_gmtoff nor timezone
160 is available, esp. if tzname is valid.
161 Richard Earnshaw <rearnsha@arm.com> has suggested using difftime to
162 calculate between gmtime and localtime (and accounting for possible
163 daylight savings time) as an alternative. */
164 tzoffset = 0L;
165 #endif
167 if ((tzoffset % 3600) == 0)
168 tzoffset = tzoffset / 3600;
170 tz1_len = strlen (tz1);
171 tz2_len = strlen (tz2);
172 tzoff_len = jint_to_charbuf (tzoff + 11, tzoffset);
173 tzid = (char *) malloc (tz1_len + tz2_len + tzoff_len + 1);
174 if (tzid == NULL) {
175 JCL_ThrowException (env, "java/lang/OutOfMemoryError",
176 "malloc() failed");
177 return 0;
180 memcpy (tzid, tz1, tz1_len);
181 memcpy (tzid + tz1_len, tzoff + 11 - tzoff_len, tzoff_len);
182 memcpy (tzid + tz1_len + tzoff_len, tz2, tz2_len);
183 tzid[tz1_len + tzoff_len + tz2_len] = '\0';
185 retval = (*env)->NewStringUTF (env, tzid);
186 free (tzid);
188 return retval;
191 /* Put printed (decimal) representation of NUM in a buffer.
192 BUFEND marks the end of the buffer, which must be at least 11 chars long.
193 Returns the COUNT of chars written. The result is in
194 (BUFEND - COUNT) (inclusive) upto (BUFEND) (exclusive).
196 Note that libgcj has a slightly different version called _Jv_FormatInt
197 that works on jchar buffers.
200 static size_t
201 jint_to_charbuf (char *bufend, jint num)
203 register char *ptr = bufend;
204 jboolean isNeg;
205 if (num < 0)
207 isNeg = JNI_TRUE;
208 num = -(num);
209 if (num < 0)
211 /* Must be MIN_VALUE, so handle this special case.
212 FIXME use 'unsigned jint' for num. */
213 *--ptr = '8';
214 num = 214748364;
217 else
218 isNeg = JNI_FALSE;
222 *--ptr = (char) ((int) '0' + (num % 10));
223 num /= 10;
225 while (num > 0);
227 if (isNeg)
228 *--ptr = '-';
229 return bufend - ptr;