1 // Time.cpp: clock and local time functions for Gnash
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
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.
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.
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
22 /// Gnash has three time implementations: one using boost::date_time,
23 /// which handles portability itself, one for POSIX systems and one for
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.
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.
36 /// @todo review this page, some bits seem obsoleted
38 #include <boost/cstdint.hpp>
39 #include "ClockTime.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
;
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
;
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.
83 #else // not using boost::date_time
85 #include <ctime> // for time_t, localtime
89 # include <sys/types.h>
90 # include <sys/timeb.h>
94 #if !defined(HAVE_TM_GMTOFF)
95 # ifdef HAVE_LONG_TIMEZONE
96 extern long timezone
; // for tzset()/long timezone;
100 /// Win32 implementation for getTicks
101 # if defined(_WIN32) || defined(WIN32)
102 # include <windows.h>
103 # include <mmsystem.h>
107 clocktime::getTicks()
109 // This needs to return milliseconds. Does it?
110 return timeGetTime();
114 # include <sys/time.h>
117 clocktime::getTicks()
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);
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).
151 clocktime::getTimeZoneOffset(double time
)
154 time_t tt
= static_cast<time_t>(time
/ 1000.0);
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
)) {
166 struct tm
*tmp
= NULL
;
167 tmp
= localtime(&tt
);
168 if (!tmp
) return 0; // We failed.
169 memcpy(&tm
, tmp
, sizeof(struct tm
));
179 #ifdef HAVE_LOCALTIME_R
180 // find out whether DST is in force
181 if (!localtime_r(&ttmp
, &tm2
)) {
185 struct tm
*tmp2
= NULL
;
186 tmp2
= localtime(&ttmp
);
187 if (!tmp2
) return 0; // We failed.
188 memcpy(&tm2
, tmp2
, sizeof(struct tm
));
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
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);
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
217 # if defined(HAVE_TZSET) && defined(HAVE_LONG_TIMEZONE)
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)
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
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.
251 // tb.timezone is number of minutes west of GMT
252 offset
= -tb
.timezone
;
256 offset
= 0; // No idea.
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
273 // tm_isdst is negative: cannot get TZ info.
274 // Convert and print in UTC instead.
276 gnash::log_error(_("Cannot get requested timezone information"));
288 #endif // Not using boost::date_time