Move "loop" related tests in their own dir. This is just to break the ice... ideally...
[gnash.git] / libbase / ClockTime.cpp
blob9bb2cd88b4f31f0136f013b4b188490a5504faf9
1 // Time.cpp: clock and local time functions for Gnash
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
4 // 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 /// \page wall_clock_time Wall clock time
21 ///
22 /// Gnash has three time implementations: one using boost::date_time,
23 /// which handles portability itself, one for POSIX systems and one for
24 /// Win32.
25 ///
26 /// Namespace clocktime contains a unified source for wall clock time: this
27 /// is used mainly for the timing of movie advances and in the ActionScript
28 /// Date class. FPS profiling also uses clocktime:: for a relatively high
29 /// resolution, robust timer.
30 ///
31 /// The boost::date_time has the great advantage of handling portability itself,
32 /// as well as being able to handle a much larger range of true dates. Its
33 /// disadvantage is that date_time requires not only header files, but also
34 /// a run-time library, and thus increases the requirements.
35 ///
36 /// @todo review this page, some bits seem obsoleted
38 #include <boost/cstdint.hpp>
39 #include "ClockTime.h"
40 #include "log.h"
42 // Define USE_BOOST_DATE_TIME to use boost as the basis for all
43 // clock time functions. The function getTimeZoneOffset() is not
44 // yet implemented for boost, but will only affect the Date class.
45 #undef USE_BOOST_DATE_TIME
47 #ifdef USE_BOOST_DATE_TIME
49 #include <boost/date_time/posix_time/posix_time.hpp>
50 #include <boost/date_time/microsec_time_clock.hpp>
52 using namespace boost::posix_time;
54 boost::uint64_t
55 clocktime::getTicks()
58 // Midnight, 1st January 1970: the Epoch.
59 static const posix_time::ptime epoch (from_time_t(0));
61 // Time between now and the Epoch.
62 posix_time::time_duration elapsed = (microsec_clock::local_time() - epoch);
64 // Divisor to convert ticks to milliseconds
65 const int denominator = time_duration::ticks_per_second() / 1000.0;
67 return elapsed.ticks() / denominator;
70 boost::int32_t
71 clocktime::getTimeZoneOffset()
73 // Obviously this doesn't work yet. Using this method
74 // may come up against the problem that boost won't handle
75 // dates outside its limits. However, ActionScript seems
76 // not to regard dates later than 2037 as having dst (this
77 // may depend on a machine-specific tz database) and there
78 // could also be a lower limit.
80 return 0;
83 #else // not using boost::date_time
85 #include <ctime> // for time_t, localtime
87 #ifdef HAVE_FTIME
88 extern "C" {
89 # include <sys/types.h>
90 # include <sys/timeb.h>
92 #endif
94 #if !defined(HAVE_TM_GMTOFF)
95 # ifdef HAVE_LONG_TIMEZONE
96 extern long timezone; // for tzset()/long timezone;
97 # endif
98 #endif
100 /// Win32 implementation for getTicks
101 # if defined(_WIN32) || defined(WIN32)
102 # include <windows.h>
103 # include <mmsystem.h>
106 boost::uint64_t
107 clocktime::getTicks()
109 // This needs to return milliseconds. Does it?
110 return timeGetTime();
113 # else // not _WIN32
114 # include <sys/time.h>
116 boost::uint64_t
117 clocktime::getTicks()
120 struct timeval tv;
122 gettimeofday(&tv, 0);
124 boost::uint64_t result = static_cast<boost::uint64_t>(tv.tv_sec) * 1000000L;
126 // Time Unit: microsecond
127 result += tv.tv_usec;
129 return static_cast<boost::uint64_t>(result / 1000.0);
132 # endif // not WIN32
134 /// Common non-boost function to return the present time offset.
135 /// This all seems like a terrible hack. It was moved from Date.cpp,
136 /// whence the following explanation also comes.
138 /// If the real mktime() sees isdst == 0 with a DST date, it sets
139 /// t_isdst and modifies the hour fields, but we need to set the
140 /// specified hour in the localtime in force at that time.
142 /// To do this we set tm_isdst to the correct value for that moment in time
143 /// by doing an initial conversion of the time to find out is_dst for that
144 /// moment without DST, then do the real conversion.
145 /// This may still get things wrong around the hour when the clocks go back
147 /// It also gets things wrong for very high or low time values, when the
148 /// localtime implementation fills the gmtoff element with 53 minutes (on
149 /// at least one machine, anyway).
150 boost::int32_t
151 clocktime::getTimeZoneOffset(double time)
154 time_t tt = static_cast<time_t>(time / 1000.0);
156 struct tm tm;
158 #ifdef HAVE_LOCALTIME_R
160 // If the requested time exceeds the limits we return 0; otherwise we'll
161 // be using uninitialized values
162 if (!localtime_r(&tt, &tm)) {
163 return 0;
165 #else
166 struct tm *tmp = NULL;
167 tmp = localtime(&tt);
168 if (!tmp) return 0; // We failed.
169 memcpy(&tm, tmp, sizeof(struct tm));
170 #endif
172 struct tm tm2 = tm;
173 tm2.tm_isdst = 0;
175 time_t ttmp = 0;
177 ttmp = mktime(&tm2);
179 #ifdef HAVE_LOCALTIME_R
180 // find out whether DST is in force
181 if (!localtime_r(&ttmp, &tm2)) {
182 return 0;
184 #else
185 struct tm *tmp2 = NULL;
186 tmp2 = localtime(&ttmp);
187 if (!tmp2) return 0; // We failed.
188 memcpy(&tm2, tmp2, sizeof(struct tm));
189 #endif
191 // If mktime or localtime fail, tm2.tm_isdst should be unchanged,
192 // so 0. That's why we don't make any checks on their success.
194 tm.tm_isdst = tm2.tm_isdst;
196 #ifdef HAVE_TM_GMTOFF
198 int offset;
200 // tm_gmtoff is in seconds east of GMT; convert to minutes.
201 offset = tm.tm_gmtoff / 60;
202 //gnash::log_debug("Using tm.tm_gmtoff. Offset is %d", offset);
203 return offset;
205 #else
207 // Find the geographical system timezone offset and add an hour if
208 // DST applies to the date.
209 // To get it really right I guess we should call both gmtime()
210 // and localtime() and look at the difference.
212 // The range of standard time is GMT-11 to GMT+14.
213 // The most extreme with DST is Chatham Island GMT+12:45 +1DST
215 int offset;
217 # if defined(HAVE_TZSET) && defined(HAVE_LONG_TIMEZONE)
219 tzset();
220 // timezone is seconds west of GMT
221 offset = -timezone / 60;
222 //gnash::log_debug("Using tzset. Offset is %d", offset);
224 # elif !defined(WIN32) && defined(HAVE_GETTIMEOFDAY)
226 // gettimeofday(3):
227 // "The use of the timezone structure is obsolete; the tz argument
228 // should normally be specified as NULL. The tz_dsttime field has
229 // never been used under Linux; it has not been and will not be
230 // supported by libc or glibc."
232 // In practice this appears to return the present time offset including dst,
233 // so adding the dst of the time specified (we do this a couple of lines
234 // down) gives the correct result when it's not presently dst, the wrong
235 // one when it is.
236 struct timeval tv;
237 struct timezone tz;
238 gettimeofday(&tv, &tz);
239 offset = -tz.tz_minuteswest;
240 //gnash::log_debug("Using gettimeofday. Offset is %d", offset);
242 # elif defined(HAVE_FTIME)
243 // ftime(3): "These days the contents of the timezone and dstflag
244 // fields are undefined."
245 // In practice, timezone is -120 in Italy when it should be -60.
246 // The problem here as for gettimeofday: the offset also includes dst.
247 struct timeb tb;
249 ftime(&tb);
251 // tb.timezone is number of minutes west of GMT
252 offset = -tb.timezone;
254 # else
256 offset = 0; // No idea.
258 # endif
260 // Adjust by one hour if DST was in force at that time.
262 // According to http://www.timeanddate.com/time/, the only place that
263 // uses DST != +1 hour is Lord Howe Island with half an hour. Tough.
265 if (tm.tm_isdst == 0) {
266 // DST exists and is not in effect
268 else if (tm.tm_isdst > 0) {
269 // DST exists and was in effect
270 offset += 60;
272 else {
273 // tm_isdst is negative: cannot get TZ info.
274 // Convert and print in UTC instead.
275 LOG_ONCE(
276 gnash::log_error(_("Cannot get requested timezone information"));
278 offset = 0;
281 return offset;
283 #endif // No gmoff
288 #endif // Not using boost::date_time