1
// Time.cpp: clock and local time functions for Gnash
3
// Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5
// This program is free software; you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation; either version 3 of the License, or
8
// (at your option) any later version.
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
// GNU General Public License for more details.
15
// You should have received a copy of the GNU General Public License
16
// along with this program; if not, write to the Free Software
17
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
/// Gnash has three time implementations: one using boost::date_time,
21
/// which handles portability itself, one for POSIX systems and one for
24
/// Namespace clocktime contains a unified source for wall clock time: this
25
/// is used mainly for the timing of movie advances and in the ActionScript
26
/// Date class. FPS profiling also uses clocktime:: for a relatively high resolution,
29
/// The boost::date_time has the great advantage of handling portability itself,
30
/// as well as being able to handle a much larger range of true dates. Its
31
/// disadvantage is that date_time requires not only header files, but also
32
/// a run-time library, and thus increases the requirements.
34
#include <boost/cstdint.hpp>
35
#include "ClockTime.h"
38
// Define USE_BOOST_DATE_TIME to use boost as the basis for all
39
// clock time functions. The function getTimeZoneOffset() is not
40
// yet implemented for boost, but will only affect the Date class.
41
#undef USE_BOOST_DATE_TIME
43
#ifdef USE_BOOST_DATE_TIME
45
#include <boost/date_time/posix_time/posix_time.hpp>
46
#include <boost/date_time/microsec_time_clock.hpp>
48
using namespace boost::posix_time;
54
// Midnight, 1st January 1970: the Epoch.
55
static const posix_time::ptime epoch (from_time_t(0));
57
// Time between now and the Epoch.
58
posix_time::time_duration elapsed = (microsec_clock::local_time() - epoch);
60
// Divisor to convert ticks to milliseconds
61
const int denominator = time_duration::ticks_per_second() / 1000.0;
63
return elapsed.ticks() / denominator;
67
clocktime::getTimeZoneOffset()
69
// Obviously this doesn't work yet. Using this method
70
// may come up against the problem that boost won't handle
71
// dates outside its limits. However, ActionScript seems
72
// not to regard dates later than 2037 as having dst (this
73
// may depend on a machine-specific tz database) and there
74
// could also be a lower limit.
79
#else // not using boost::date_time
81
#include <ctime> // for time_t, localtime
83
#if !defined(HAVE_GETTIMEOFDAY) || (!defined(HAVE_TM_GMTOFF) && !defined(HAVE_TZSET))
86
# include <sys/types.h> // for ftime()
87
# include <sys/timeb.h> // for ftime()
92
#if !defined(HAVE_TM_GMTOFF)
93
# ifdef HAVE_LONG_TIMEZONE
94
extern long timezone; // for tzset()/long timezone;
98
/// Win32 implementation for getTicks
99
# if defined(_WIN32) || defined(WIN32)
100
# include <windows.h>
101
# include <mmsystem.h>
105
clocktime::getTicks()
107
// This needs to return milliseconds. Does it?
108
return timeGetTime();
112
# include <sys/time.h>
115
clocktime::getTicks()
120
gettimeofday(&tv, 0);
122
boost::uint64_t result = static_cast<boost::uint64_t>(tv.tv_sec) * 1000000L;
124
// Time Unit: microsecond
125
result += tv.tv_usec;
127
return static_cast<boost::uint64_t>(result / 1000.0);
132
/// Common non-boost function to return the present time offset.
133
/// This all seems like a terrible hack. It was moved from Date.cpp,
134
/// whence the following explanation also comes.
136
/// If the real mktime() sees isdst == 0 with a DST date, it sets
137
/// t_isdst and modifies the hour fields, but we need to set the
138
/// specified hour in the localtime in force at that time.
140
/// To do this we set tm_isdst to the correct value for that moment in time
141
/// by doing an initial conversion of the time to find out is_dst for that
142
/// moment without DST, then do the real conversion.
143
/// This may still get things wrong around the hour when the clocks go back
145
/// It also gets things wrong for very high or low time values, when the
146
/// localtime implementation fills the gmtoff element with 53 minutes (on
147
/// at least one machine, anyway).
149
clocktime::getTimeZoneOffset(double time)
152
time_t tt = static_cast<time_t>(time / 1000.0);
156
#ifdef HAVE_LOCALTIME_R
157
localtime_r(&tt, &tm);
159
struct tm *tmp = NULL;
160
tmp = localtime(&tt);
161
if (!tmp) return 0; // We failed.
162
memcpy(&tm, tmp, sizeof(struct tm));
172
#ifdef HAVE_LOCALTIME_R
173
localtime_r(&ttmp, &tm2); // find out whether DST is in force
175
struct tm *tmp2 = NULL;
176
tmp2 = localtime(&ttmp);
177
if (!tmp2) return 0; // We failed.
178
memcpy(&tm2, tmp2, sizeof(struct tm));
181
// If mktime or localtime fail, tm2.tm_isdst should be unchanged,
182
// so 0. That's why we don't make any checks on their success.
184
tm.tm_isdst = tm2.tm_isdst;
186
#ifdef HAVE_TM_GMTOFF
190
// tm_gmtoff is in seconds east of GMT; convert to minutes.
191
offset = tm.tm_gmtoff / 60;
192
//gnash::log_debug("Using tm.tm_gmtoff. Offset is %d", offset);
197
// Find the geographical system timezone offset and add an hour if
198
// DST applies to the date.
199
// To get it really right I guess we should call both gmtime()
200
// and localtime() and look at the difference.
202
// The range of standard time is GMT-11 to GMT+14.
203
// The most extreme with DST is Chatham Island GMT+12:45 +1DST
207
# if defined(HAVE_TZSET) && defined(HAVE_LONG_TIMEZONE)
210
// timezone is seconds west of GMT
211
offset = -timezone / 60;
212
//gnash::log_debug("Using tzset. Offset is %d", offset);
214
# elif defined(HAVE_GETTIMEOFDAY)
217
// "The use of the timezone structure is obsolete; the tz argument
218
// should normally be specified as NULL. The tz_dsttime field has
219
// never been used under Linux; it has not been and will not be
220
// supported by libc or glibc."
221
// Still, mancansa d'asu, t'acuma i buoi (Mangels Esel, Ochsen einspannen...)
223
// In practice this appears to return the present time offset including dst,
224
// so adding the dst of the time specified (we do this a couple of lines down)
225
// gives the correct result when it's not presently dst, the wrong one when
229
gettimeofday(&tv, &tz);
230
offset = -tz.tz_minuteswest;
231
//gnash::log_debug("Using gettimeofday. Offset is %d", offset);
233
# elif defined(HAVE_FTIME)
234
// ftime(3): "These days the contents of the timezone and dstflag
235
// fields are undefined."
236
// In practice, timezone is -120 in Italy when it should be -60.
237
// The problem here as for gettimeofday: the offset also includes dst.
241
// tb.timezone is number of minutes west of GMT
242
offset = -tb.timezone;
243
//gnash::log_debug("Using ftime. Offset is %d", offset);
247
offset = 0; // No idea.
248
//gnash::log_debug("Cannot find offset. Offset is %d", offset);
252
// Adjust by one hour if DST was in force at that time.
254
// According to http://www.timeanddate.com/time/, the only place that
255
// uses DST != +1 hour is Lord Howe Island with half an hour. Tough.
257
if (tm.tm_isdst == 0) {
258
// DST exists and is not in effect
260
else if (tm.tm_isdst > 0) {
261
// DST exists and was in effect
265
// tm_isdst is negative: cannot get TZ info.
266
// Convert and print in UTC instead.
268
gnash::log_error(_("Cannot get requested timezone information"));
280
#endif // Not using boost::date_time