xref: /reactos/sdk/lib/crt/time/timezone.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:   LGPL, See LGPL.txt in the top level directory
3  * PROJECT:     ReactOS CRT library
4  * FILE:        lib/sdk/crt/time/timezone.c
5  * PURPOSE:     Implementation of time zone functions
6  * PROGRAMERS:  Timo Kreuzer
7  */
8 #include "precomp.h"
9 
10 char _tz_is_set = 0;
11 
12 /* buffers must hold 64 characters! */
13 static char tz_name[64] = "PST";
14 static char tz_dst_name[64] = "PDT";
15 
16 long dst_begin = 0;
17 long dst_end = 0;
18 
19 /******************************************************************************
20  * \var _tzname
21  */
22 char * _tzname[2] = {
23   tz_name,
24   tz_dst_name,
25 };
26 
27 /******************************************************************************
28  * \var _daylight
29  */
30 int _daylight = 0;
31 
32 /******************************************************************************
33  * \name __p__daylight
34  * \brief Returns a pointer to the _daylight variable;
35  */
36 void *
__p__daylight(void)37 __p__daylight(void)
38 {
39    return &_daylight;
40 }
41 
42 /******************************************************************************
43  * \var _timezone
44  * \brief
45  */
46 long _timezone = 28800;
47 
48 /******************************************************************************
49  * \name __p__timezone
50  * \brief Returns a pointer to the _timezone variable;
51  */
52 long *
__p__timezone(void)53 __p__timezone(void)
54 {
55    return &_timezone;
56 }
57 
58 /******************************************************************************
59  * \var _dstbias
60  * \brief
61  */
62 long _dstbias = 0;
63 
64 /******************************************************************************
65  * \name __p__dstbias
66  * \brief Returns a pointer to the _dstbias variable;
67  */
68 long *
__p__dstbias(void)69 __p__dstbias(void)
70 {
71     return &_dstbias;
72 }
73 
74 /******************************************************************************
75  * \name __p__tzname
76  * \brief Returns a pointer to the _tzname buffer;
77  */
78 char **
__p__tzname(void)79 __p__tzname(void)
80 {
81     return _tzname;
82 }
83 
84 /******************************************************************************
85  * \name _tzset
86  * \brief Initializes the variables _daylight, _timezone, and _tzname from the
87  *        "TZ" environment variable if available or else by calling
88  *        GetTimeZoneInformation.
89  * \sa http://msdn.microsoft.com/en-us/library/90s5c885.aspx
90  */
91 void
_tzset(void)92 _tzset(void)
93 {
94     const char * str;
95 
96     if (_tz_is_set)
97     {
98         return;
99     }
100 
101     /* Try to read the timezone from environment */
102     str = getenv("TZ");
103     if (str && str[0] != 0)
104     {
105         long hour = 0, min = 0, sec = 0;
106         size_t len = strnlen(str, 16);
107         int sign = 1;
108 
109         dst_begin = 0;
110 
111         for (;;)
112         {
113             /* Copy timezone name */
114             strncpy(tz_name, str, 3);
115             str += 3;
116             len -= 3;
117 
118             if (len < 1) break;
119 
120             if (*str == '+' || *str == '-')
121             {
122                 sign = *str == '-' ? -1 : 1;
123                 str++;
124                 len--;
125             }
126 
127             if (len < 1) break;
128 
129             hour = atol(str);
130 
131             while (*str != 0 && *str != ':') str++;
132             if (*str == 0) break;
133 
134             min = atol(++str);
135 
136             while (*str != 0 && *str != ':') str++;
137             if (*str == 0) break;
138 
139             sec = atol(++str);
140 
141             while (*str != 0 && *str <= '9') str++;
142             if (*str == 0) break;
143 
144             /* Copy DST name */
145             strncpy(tz_dst_name, str, 3);
146 
147             // FIXME: set dst_begin etc
148 
149             /* We are finished */
150             break;
151         }
152 
153         _timezone = sign * (((hour * 60) + min) * 60 + sec);
154 
155     }
156     else
157     {
158         TIME_ZONE_INFORMATION tzi;
159         DWORD ret;
160 
161         ret = GetTimeZoneInformation(&tzi);
162         if (ret == TIME_ZONE_ID_INVALID)
163         {
164             return;
165         }
166 
167         ret = WideCharToMultiByte(CP_ACP,
168                                   0,
169                                   tzi.StandardName,
170                                   -1,
171                                   tz_name,
172                                   sizeof(tz_name),
173                                   NULL,
174                                   NULL);
175 
176         ret = WideCharToMultiByte(CP_ACP,
177                                   0,
178                                   tzi.DaylightName,
179                                   -1,
180                                   tz_dst_name,
181                                   sizeof(tz_dst_name),
182                                   NULL,
183                                   NULL);
184 
185         _timezone = tzi.Bias * 60;
186 
187         if (tzi.DaylightDate.wMonth)
188         {
189             struct tm _tm;
190 
191             _daylight = 1;
192             _dstbias = (tzi.DaylightBias - tzi.StandardBias) * 60;
193             _tm.tm_year = 70;
194             _tm.tm_mon = tzi.DaylightDate.wMonth - 1;
195             _tm.tm_mday = tzi.DaylightDate.wDay;
196             _tm.tm_hour = tzi.DaylightDate.wHour;
197             _tm.tm_min = tzi.DaylightDate.wMinute;
198             _tm.tm_sec = tzi.DaylightDate.wSecond;
199             dst_begin = (long)_mkgmtime(&_tm);
200             _tm.tm_mon = tzi.StandardDate.wMonth - 1;
201             _tm.tm_mday = tzi.StandardDate.wDay;
202             _tm.tm_hour = tzi.StandardDate.wHour;
203             _tm.tm_min = tzi.StandardDate.wMinute;
204             _tm.tm_sec = tzi.StandardDate.wSecond;
205             dst_end = (long)_mkgmtime(&_tm);
206         }
207         else
208         {
209             _daylight = 0;
210             _dstbias = 0;
211         }
212 
213     }
214     _tz_is_set = 1;
215 }
216 
217 /*********************************************************************
218  *		_get_tzname (MSVCRT.@)
219  */
_get_tzname(size_t * ret,char * buf,size_t bufsize,int index)220 int CDECL _get_tzname(size_t *ret, char *buf, size_t bufsize, int index)
221 {
222     char *str_timezone;
223 
224     switch (index)
225     {
226     case 0:
227         str_timezone = tz_name;
228         break;
229 
230     case 1:
231         str_timezone = tz_dst_name;
232         break;
233 
234     default:
235         *_errno() = EINVAL;
236         return EINVAL;
237     }
238 
239     if (!ret || (!buf && (bufsize > 0)) || (buf && !bufsize))
240     {
241         *_errno() = EINVAL;
242         return EINVAL;
243     }
244 
245     *ret = strlen(str_timezone) + 1;
246     if(!buf && !bufsize)
247         return 0;
248 
249     strncpy(buf, str_timezone, bufsize);
250     return 0;
251 }
252