Call tzset() for all compilers before using time zone variable.
[wxWidgets.git] / src / common / time.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/time.cpp
3 // Purpose: Implementation of time-related functions.
4 // Author: Vadim Zeitlin
5 // Created: 2011-11-26
6 // RCS-ID: $Id: wxhead.cpp,v 1.11 2010-04-22 12:44:51 zeitlin Exp $
7 // Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #include "wx/time.h"
27
28 #ifndef WX_PRECOMP
29 #ifdef __WXMSW__
30 #include "wx/msw/wrapwin.h"
31 #endif
32 #include "wx/intl.h"
33 #include "wx/log.h"
34 #endif
35
36 #ifndef WX_GMTOFF_IN_TM
37 // Define it for some systems which don't (always) use configure but are
38 // known to have tm_gmtoff field.
39 #if defined(__WXPALMOS__) || defined(__DARWIN__)
40 #define WX_GMTOFF_IN_TM
41 #endif
42 #endif
43
44 #if defined(__VISAGECPP__) && !defined(HAVE_FTIME)
45 #define HAVE_FTIME
46 # if __IBMCPP__ >= 400
47 # define ftime(x) _ftime(x)
48 # endif
49 #endif
50
51 #if defined(__MWERKS__) && defined(__WXMSW__)
52 # undef HAVE_FTIME
53 # undef HAVE_GETTIMEOFDAY
54 #endif
55
56 #ifndef __WXPALMOS5__
57 #ifndef __WXWINCE__
58 #include <time.h>
59 #else
60 #include "wx/msw/private.h"
61 #include "wx/msw/wince/time.h"
62 #endif
63 #endif // __WXPALMOS5__
64
65
66 #if !defined(__WXMAC__) && !defined(__WXWINCE__)
67 #include <sys/types.h> // for time_t
68 #endif
69
70 #if defined(HAVE_GETTIMEOFDAY)
71 #include <sys/time.h>
72 #include <unistd.h>
73 #elif defined(HAVE_FTIME)
74 #include <sys/timeb.h>
75 #endif
76
77 #ifdef __WXPALMOS__
78 #include <DateTime.h>
79 #include <TimeMgr.h>
80 #include <SystemMgr.h>
81 #endif
82
83 #if defined(__MWERKS__) && wxUSE_UNICODE
84 #include <wtime.h>
85 #endif
86
87 #if defined(__DJGPP__) || defined(__WINE__)
88 #include <sys/timeb.h>
89 #include <values.h>
90 #endif
91
92 namespace
93 {
94
95 const int MILLISECONDS_PER_SECOND = 1000;
96 const int MICROSECONDS_PER_MILLISECOND = 1000;
97 const int MICROSECONDS_PER_SECOND = 1000*1000;
98
99 } // anonymous namespace
100
101 // ============================================================================
102 // implementation
103 // ============================================================================
104
105 // NB: VC8 safe time functions could/should be used for wxMSW as well probably
106 #if defined(__WXWINCE__) && defined(__VISUALC8__)
107
108 struct tm *wxLocaltime_r(const time_t *t, struct tm* tm)
109 {
110 __time64_t t64 = *t;
111 return _localtime64_s(tm, &t64) == 0 ? tm : NULL;
112 }
113
114 struct tm *wxGmtime_r(const time_t* t, struct tm* tm)
115 {
116 __time64_t t64 = *t;
117 return _gmtime64_s(tm, &t64) == 0 ? tm : NULL;
118 }
119
120 #else // !wxWinCE with VC8
121
122 #if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__)
123 static wxMutex timeLock;
124 #endif
125
126 #ifndef HAVE_LOCALTIME_R
127 struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp)
128 {
129 #if wxUSE_THREADS && !defined(__WINDOWS__)
130 // No need to waste time with a mutex on windows since it's using
131 // thread local storage for localtime anyway.
132 wxMutexLocker locker(timeLock);
133 #endif
134
135 // Borland CRT crashes when passed 0 ticks for some reason, see SF bug 1704438
136 #ifdef __BORLANDC__
137 if ( !*ticks )
138 return NULL;
139 #endif
140
141 const tm * const t = localtime(ticks);
142 if ( !t )
143 return NULL;
144
145 memcpy(temp, t, sizeof(struct tm));
146 return temp;
147 }
148 #endif // !HAVE_LOCALTIME_R
149
150 #ifndef HAVE_GMTIME_R
151 struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp)
152 {
153 #if wxUSE_THREADS && !defined(__WINDOWS__)
154 // No need to waste time with a mutex on windows since it's
155 // using thread local storage for gmtime anyway.
156 wxMutexLocker locker(timeLock);
157 #endif
158
159 #ifdef __BORLANDC__
160 if ( !*ticks )
161 return NULL;
162 #endif
163
164 const tm * const t = gmtime(ticks);
165 if ( !t )
166 return NULL;
167
168 memcpy(temp, gmtime(ticks), sizeof(struct tm));
169 return temp;
170 }
171 #endif // !HAVE_GMTIME_R
172
173 #endif // wxWinCE with VC8/other platforms
174
175 // returns the time zone in the C sense, i.e. the difference UTC - local
176 // (in seconds)
177 int wxGetTimeZone()
178 {
179 #ifdef WX_GMTOFF_IN_TM
180 // set to true when the timezone is set
181 static bool s_timezoneSet = false;
182 static long gmtoffset = LONG_MAX; // invalid timezone
183
184 // ensure that the timezone variable is set by calling wxLocaltime_r
185 if ( !s_timezoneSet )
186 {
187 // just call wxLocaltime_r() instead of figuring out whether this
188 // system supports tzset(), _tzset() or something else
189 time_t t = time(NULL);
190 struct tm tm;
191
192 wxLocaltime_r(&t, &tm);
193 s_timezoneSet = true;
194
195 // note that GMT offset is the opposite of time zone and so to return
196 // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM
197 // cases we have to negate it
198 gmtoffset = -tm.tm_gmtoff;
199
200 // this function is supposed to return the same value whether DST is
201 // enabled or not, so we need to use an additional offset if DST is on
202 // as tm_gmtoff already does include it
203 if ( tm.tm_isdst )
204 gmtoffset += 3600;
205 }
206 return (int)gmtoffset;
207 #elif defined(__DJGPP__) || defined(__WINE__)
208 struct timeb tb;
209 ftime(&tb);
210 return tb.timezone*60;
211 #elif defined(__VISUALC__)
212 // We must initialize the time zone information before using it (this will
213 // be done only once internally).
214 _tzset();
215
216 // Starting with VC++ 8 timezone variable is deprecated and is not even
217 // available in some standard library version so use the new function for
218 // accessing it instead.
219 #if wxCHECK_VISUALC_VERSION(8)
220 long t;
221 _get_timezone(&t);
222 return t;
223 #else // VC++ < 8
224 return timezone;
225 #endif
226 #else // Use some kind of time zone variable.
227 // In any case we must initialize the time zone before using it.
228 tzset();
229
230 #if defined(WX_TIMEZONE) // If WX_TIMEZONE was defined by configure, use it.
231 return WX_TIMEZONE;
232 #elif defined(__BORLANDC__) || defined(__MINGW32__) || defined(__VISAGECPP__)
233 return _timezone;
234 #elif defined(__MWERKS__)
235 // This is just plain wrong but apparently MetroWerks runtime didn't have
236 // any way to get the time zone.
237 return 28800;
238 #else // unknown platform -- assume it has timezone
239 return timezone;
240 #endif // different time zone variables
241 #endif // different ways to determine time zone
242 }
243
244 // Get local time as seconds since 00:00:00, Jan 1st 1970
245 long wxGetLocalTime()
246 {
247 struct tm tm;
248 time_t t0, t1;
249
250 // This cannot be made static because mktime can overwrite it.
251 //
252 memset(&tm, 0, sizeof(tm));
253 tm.tm_year = 70;
254 tm.tm_mon = 0;
255 tm.tm_mday = 5; // not Jan 1st 1970 due to mktime 'feature'
256 tm.tm_hour = 0;
257 tm.tm_min = 0;
258 tm.tm_sec = 0;
259 tm.tm_isdst = -1; // let mktime guess
260
261 // Note that mktime assumes that the struct tm contains local time.
262 //
263 t1 = time(&t1); // now
264 t0 = mktime(&tm); // origin
265
266 // Return the difference in seconds.
267 //
268 if (( t0 != (time_t)-1 ) && ( t1 != (time_t)-1 ))
269 return (long)difftime(t1, t0) + (60 * 60 * 24 * 4);
270
271 wxLogSysError(_("Failed to get the local system time"));
272 return -1;
273 }
274
275 // Get UTC time as seconds since 00:00:00, Jan 1st 1970
276 long wxGetUTCTime()
277 {
278 return (long)time(NULL);
279 }
280
281 #if wxUSE_LONGLONG
282
283 wxLongLong wxGetUTCTimeUSec()
284 {
285 #if defined(__WXMSW__)
286 FILETIME ft;
287 ::GetSystemTimeAsFileTime(&ft);
288
289 // FILETIME is in 100ns or 0.1us since 1601-01-01, transform to us since
290 // 1970-01-01.
291 wxLongLong t(ft.dwHighDateTime, ft.dwLowDateTime);
292 t /= 10;
293 t -= wxLL(11644473600000000); // Unix - Windows epochs difference in us.
294 return t;
295 #else // non-MSW
296
297 #ifdef HAVE_GETTIMEOFDAY
298 timeval tv;
299 if ( wxGetTimeOfDay(&tv) != -1 )
300 {
301 wxLongLong val(tv.tv_sec);
302 val *= MICROSECONDS_PER_SECOND;
303 val += tv.tv_usec;
304 return val;
305 }
306 #endif // HAVE_GETTIMEOFDAY
307
308 // Fall back to lesser precision function.
309 return wxGetUTCTimeMillis()*MICROSECONDS_PER_MILLISECOND;
310 #endif // MSW/!MSW
311 }
312
313 // Get local time as milliseconds since 00:00:00, Jan 1st 1970
314 wxLongLong wxGetUTCTimeMillis()
315 {
316 wxLongLong val = MILLISECONDS_PER_SECOND;
317
318 // If possible, use a function which avoids conversions from
319 // broken-up time structures to milliseconds
320 #if defined(__WXPALMOS__)
321 DateTimeType thenst;
322 thenst.second = 0;
323 thenst.minute = 0;
324 thenst.hour = 0;
325 thenst.day = 1;
326 thenst.month = 1;
327 thenst.year = 1970;
328 thenst.weekDay = 5;
329 uint32_t now = TimGetSeconds();
330 uint32_t then = TimDateTimeToSeconds (&thenst);
331 return SysTimeToMilliSecs(SysTimeInSecs(now - then));
332 #elif defined(__WXMSW__)
333 FILETIME ft;
334 ::GetSystemTimeAsFileTime(&ft);
335
336 // FILETIME is expressed in 100ns (or 0.1us) units since 1601-01-01,
337 // transform them to ms since 1970-01-01.
338 wxLongLong t(ft.dwHighDateTime, ft.dwLowDateTime);
339 t /= 10000;
340 t -= wxLL(11644473600000); // Unix - Windows epochs difference in ms.
341 return t;
342 #elif defined(HAVE_GETTIMEOFDAY)
343 struct timeval tp;
344 if ( wxGetTimeOfDay(&tp) != -1 )
345 {
346 val *= tp.tv_sec;
347 return (val + (tp.tv_usec / MICROSECONDS_PER_MILLISECOND));
348 }
349 else
350 {
351 wxLogError(_("wxGetTimeOfDay failed."));
352 return 0;
353 }
354 #elif defined(HAVE_FTIME)
355 struct timeb tp;
356
357 // ftime() is void and not int in some mingw32 headers, so don't
358 // test the return code (well, it shouldn't fail anyhow...)
359 (void)::ftime(&tp);
360 val *= tp.time;
361 return (val + tp.millitm);
362 #else // no gettimeofday() nor ftime()
363 // If your platform/compiler does not support ms resolution please
364 // do NOT just shut off these warnings, drop me a line instead at
365 // <guille@iies.es>
366
367 #if defined(__VISUALC__) || defined (__WATCOMC__)
368 #pragma message("wxStopWatch will be up to second resolution!")
369 #elif defined(__BORLANDC__)
370 #pragma message "wxStopWatch will be up to second resolution!"
371 #else
372 #warning "wxStopWatch will be up to second resolution!"
373 #endif // compiler
374
375 val *= wxGetUTCTime();
376 return val;
377 #endif // time functions
378 }
379
380 wxLongLong wxGetLocalTimeMillis()
381 {
382 return wxGetUTCTimeMillis() - wxGetTimeZone()*MILLISECONDS_PER_SECOND;
383 }
384
385 #else // !wxUSE_LONGLONG
386
387 double wxGetLocalTimeMillis(void)
388 {
389 return (double(clock()) / double(CLOCKS_PER_SEC)) * 1000.0;
390 }
391
392 #endif // wxUSE_LONGLONG/!wxUSE_LONGLONG