update copyright date
[gnash.git] / libbase / ClockTime.cpp
blob168668a90ac16affb049575de525db7b336971ef
1 // ClockTime.cpp: clock and local time functions for Gnash
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
4 // 2011 Free Software Foundation, Inc
5 //
6 // This program 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 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <boost/cstdint.hpp>
21 #include "ClockTime.h"
22 #include "log.h"
24 #include <ctime> // for time_t, localtime
26 #ifdef HAVE_FTIME
27 extern "C" {
28 # include <sys/types.h>
29 # include <sys/timeb.h>
31 #endif
33 #if !defined(HAVE_TM_GMTOFF)
34 # ifdef HAVE_LONG_TIMEZONE
35 extern long timezone; // for tzset()/long timezone;
36 # endif
37 #endif
39 /// Win32 implementation for getTicks
40 # if defined(_WIN32) || defined(WIN32)
41 # include <windows.h>
42 # include <mmsystem.h>
44 namespace gnash {
46 boost::uint64_t
47 clocktime::getTicks()
49 // This needs to return milliseconds. Does it?
50 return timeGetTime();
55 # else // not _WIN32
56 # include <sys/time.h>
58 namespace gnash {
60 boost::uint64_t
61 clocktime::getTicks()
64 struct timeval tv;
66 gettimeofday(&tv, 0);
68 boost::uint64_t result = static_cast<boost::uint64_t>(tv.tv_sec) * 1000000L;
70 // Time Unit: microsecond
71 result += tv.tv_usec;
73 return static_cast<boost::uint64_t>(result / 1000.0);
78 # endif // not WIN32
80 namespace gnash {
82 /// Common non-boost function to return the present time offset.
83 /// This all seems like a terrible hack. It was moved from Date.cpp,
84 /// whence the following explanation also comes.
85 ///
86 /// If the real mktime() sees isdst == 0 with a DST date, it sets
87 /// t_isdst and modifies the hour fields, but we need to set the
88 /// specified hour in the localtime in force at that time.
89 ///
90 /// To do this we set tm_isdst to the correct value for that moment in time
91 /// by doing an initial conversion of the time to find out is_dst for that
92 /// moment without DST, then do the real conversion.
93 /// This may still get things wrong around the hour when the clocks go back
94 ///
95 /// It also gets things wrong for very high or low time values, when the
96 /// localtime implementation fills the gmtoff element with 53 minutes (on
97 /// at least one machine, anyway).
98 boost::int32_t
99 clocktime::getTimeZoneOffset(double time)
102 time_t tt = static_cast<time_t>(time / 1000.0);
104 struct tm tm;
106 #ifdef HAVE_LOCALTIME_R
108 // If the requested time exceeds the limits we return 0; otherwise we'll
109 // be using uninitialized values
110 if (!localtime_r(&tt, &tm)) {
111 return 0;
113 #else
114 struct tm *tmp = NULL;
115 tmp = localtime(&tt);
116 if (!tmp) return 0; // We failed.
117 memcpy(&tm, tmp, sizeof(struct tm));
118 #endif
120 struct tm tm2 = tm;
121 tm2.tm_isdst = 0;
123 time_t ttmp = 0;
125 ttmp = mktime(&tm2);
127 #ifdef HAVE_LOCALTIME_R
128 // find out whether DST is in force
129 if (!localtime_r(&ttmp, &tm2)) {
130 return 0;
132 #else
133 struct tm *tmp2 = NULL;
134 tmp2 = localtime(&ttmp);
135 if (!tmp2) return 0; // We failed.
136 memcpy(&tm2, tmp2, sizeof(struct tm));
137 #endif
139 // If mktime or localtime fail, tm2.tm_isdst should be unchanged,
140 // so 0. That's why we don't make any checks on their success.
142 tm.tm_isdst = tm2.tm_isdst;
144 #ifdef HAVE_TM_GMTOFF
146 int offset;
148 // tm_gmtoff is in seconds east of GMT; convert to minutes.
149 offset = tm.tm_gmtoff / 60;
150 //gnash::log_debug("Using tm.tm_gmtoff. Offset is %d", offset);
151 return offset;
153 #else
155 // Find the geographical system timezone offset and add an hour if
156 // DST applies to the date.
157 // To get it really right I guess we should call both gmtime()
158 // and localtime() and look at the difference.
160 // The range of standard time is GMT-11 to GMT+14.
161 // The most extreme with DST is Chatham Island GMT+12:45 +1DST
163 int offset;
165 # if defined(HAVE_TZSET) && defined(HAVE_LONG_TIMEZONE)
167 tzset();
168 // timezone is seconds west of GMT
169 offset = -timezone / 60;
170 //gnash::log_debug("Using tzset. Offset is %d", offset);
172 # elif !defined(WIN32) && defined(HAVE_GETTIMEOFDAY)
174 // gettimeofday(3):
175 // "The use of the timezone structure is obsolete; the tz argument
176 // should normally be specified as NULL. The tz_dsttime field has
177 // never been used under Linux; it has not been and will not be
178 // supported by libc or glibc."
180 // In practice this appears to return the present time offset including dst,
181 // so adding the dst of the time specified (we do this a couple of lines
182 // down) gives the correct result when it's not presently dst, the wrong
183 // one when it is.
184 struct timeval tv;
185 struct timezone tz;
186 gettimeofday(&tv, &tz);
187 offset = -tz.tz_minuteswest;
188 //gnash::log_debug("Using gettimeofday. Offset is %d", offset);
190 # elif defined(HAVE_FTIME)
191 // ftime(3): "These days the contents of the timezone and dstflag
192 // fields are undefined."
193 // In practice, timezone is -120 in Italy when it should be -60.
194 // The problem here as for gettimeofday: the offset also includes dst.
195 struct timeb tb;
197 ftime(&tb);
199 // tb.timezone is number of minutes west of GMT
200 offset = -tb.timezone;
202 # else
204 offset = 0; // No idea.
206 # endif
208 // Adjust by one hour if DST was in force at that time.
210 // According to http://www.timeanddate.com/time/, the only place that
211 // uses DST != +1 hour is Lord Howe Island with half an hour. Tough.
213 if (tm.tm_isdst == 0) {
214 // DST exists and is not in effect
216 else if (tm.tm_isdst > 0) {
217 // DST exists and was in effect
218 offset += 60;
220 else {
221 // tm_isdst is negative: cannot get TZ info.
222 // Convert and print in UTC instead.
223 LOG_ONCE(
224 gnash::log_error(_("Cannot get requested timezone information"));
226 offset = 0;
229 return offset;
231 #endif // No gmoff
234 } // namespace gnash