Backed out 15 changesets (bug 1852806) for causing mda failures on test_video_low_pow...
[gecko.git] / js / src / vm / Time.cpp
blobad3e4e74769b8f54736f855f1ace4fdc15ae97cd
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* PR time code. */
9 #include "vm/Time.h"
11 #ifdef SOLARIS
12 # define _REENTRANT 1
13 #endif
14 #include <string.h>
15 #include <time.h>
17 #include "jstypes.h"
19 #ifdef XP_WIN
20 # include <windef.h>
21 # include <winbase.h>
22 # include <crtdbg.h> /* for _CrtSetReportMode */
23 # include <stdlib.h> /* for _set_invalid_parameter_handler */
24 #endif
26 #ifdef XP_UNIX
28 # ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
29 extern int gettimeofday(struct timeval* tv);
30 # endif
32 # include <sys/time.h>
34 #endif /* XP_UNIX */
36 #if defined(XP_UNIX)
37 int64_t PRMJ_Now() {
38 struct timeval tv;
40 # ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
41 gettimeofday(&tv);
42 # else
43 gettimeofday(&tv, 0);
44 # endif /* _SVID_GETTOD */
46 return int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec);
49 #else
51 # if _WIN32_WINNT < _WIN32_WINNT_WIN8
52 extern "C" WINBASEAPI void WINAPI GetSystemTimePreciseAsFileTime(LPFILETIME);
53 # endif
55 // Returns the number of microseconds since the Unix epoch.
56 static int64_t FileTimeToUnixMicroseconds(const FILETIME& ft) {
57 // Get the time in 100ns intervals.
58 int64_t t = (int64_t(ft.dwHighDateTime) << 32) | int64_t(ft.dwLowDateTime);
60 // The Windows epoch is around 1600. The Unix epoch is around 1970.
61 // Subtract the difference.
62 static const int64_t TimeToEpochIn100ns = 0x19DB1DED53E8000;
63 t -= TimeToEpochIn100ns;
65 // Divide by 10 to convert to microseconds.
66 return t / 10;
69 int64_t PRMJ_Now() {
70 FILETIME ft;
71 GetSystemTimePreciseAsFileTime(&ft);
72 return FileTimeToUnixMicroseconds(ft);
74 #endif
76 #if !JS_HAS_INTL_API
77 # ifdef XP_WIN
78 static void PRMJ_InvalidParameterHandler(const wchar_t* expression,
79 const wchar_t* function,
80 const wchar_t* file, unsigned int line,
81 uintptr_t pReserved) {
82 /* empty */
84 # endif
86 /* Format a time value into a buffer. Same semantics as strftime() */
87 size_t PRMJ_FormatTime(char* buf, size_t buflen, const char* fmt,
88 const PRMJTime* prtm, int timeZoneYear,
89 int offsetInSeconds) {
90 size_t result = 0;
91 # if defined(XP_UNIX) || defined(XP_WIN)
92 struct tm a;
93 # ifdef XP_WIN
94 _invalid_parameter_handler oldHandler;
95 # ifndef __MINGW32__
96 int oldReportMode;
97 # endif // __MINGW32__
98 # endif // XP_WIN
100 memset(&a, 0, sizeof(struct tm));
102 a.tm_sec = prtm->tm_sec;
103 a.tm_min = prtm->tm_min;
104 a.tm_hour = prtm->tm_hour;
105 a.tm_mday = prtm->tm_mday;
106 a.tm_mon = prtm->tm_mon;
107 a.tm_wday = prtm->tm_wday;
110 * On systems where |struct tm| has members tm_gmtoff and tm_zone, we
111 * must fill in those values, or else strftime will return wrong results
112 * (e.g., bug 511726, bug 554338).
114 # if defined(HAVE_LOCALTIME_R) && defined(HAVE_TM_ZONE_TM_GMTOFF)
115 char emptyTimeZoneId[] = "";
118 * Fill out |td| to the time represented by |prtm|, leaving the
119 * timezone fields zeroed out. localtime_r will then fill in the
120 * timezone fields for that local time according to the system's
121 * timezone parameters. Use |timeZoneYear| for the year to ensure the
122 * time zone name matches the time zone offset used by the caller.
124 struct tm td;
125 memset(&td, 0, sizeof(td));
126 td.tm_sec = prtm->tm_sec;
127 td.tm_min = prtm->tm_min;
128 td.tm_hour = prtm->tm_hour;
129 td.tm_mday = prtm->tm_mday;
130 td.tm_mon = prtm->tm_mon;
131 td.tm_wday = prtm->tm_wday;
132 td.tm_year = timeZoneYear - 1900;
133 td.tm_yday = prtm->tm_yday;
134 td.tm_isdst = prtm->tm_isdst;
136 time_t t = mktime(&td);
138 // If either mktime or localtime_r failed, fill in the fallback time
139 // zone offset |offsetInSeconds| and set the time zone identifier to
140 // the empty string.
141 if (t != static_cast<time_t>(-1) && localtime_r(&t, &td)) {
142 a.tm_gmtoff = td.tm_gmtoff;
143 a.tm_zone = td.tm_zone;
144 } else {
145 a.tm_gmtoff = offsetInSeconds;
146 a.tm_zone = emptyTimeZoneId;
149 # endif
152 * Years before 1900 and after 9999 cause strftime() to abort on Windows.
153 * To avoid that we replace it with FAKE_YEAR_BASE + year % 100 and then
154 * replace matching substrings in the strftime() result with the real year.
155 * Note that FAKE_YEAR_BASE should be a multiple of 100 to make 2-digit
156 * year formats (%y) work correctly (since we won't find the fake year
157 * in that case).
159 constexpr int FAKE_YEAR_BASE = 9900;
160 int fake_tm_year = 0;
161 if (prtm->tm_year < 1900 || prtm->tm_year > 9999) {
162 fake_tm_year = FAKE_YEAR_BASE + prtm->tm_year % 100;
163 a.tm_year = fake_tm_year - 1900;
164 } else {
165 a.tm_year = prtm->tm_year - 1900;
167 a.tm_yday = prtm->tm_yday;
168 a.tm_isdst = prtm->tm_isdst;
171 * Even with the above, SunOS 4 seems to detonate if tm_zone and tm_gmtoff
172 * are null. This doesn't quite work, though - the timezone is off by
173 * tzoff + dst. (And mktime seems to return -1 for the exact dst
174 * changeover time.)
177 # ifdef XP_WIN
178 oldHandler = _set_invalid_parameter_handler(PRMJ_InvalidParameterHandler);
179 # ifndef __MINGW32__
181 * MinGW doesn't have _CrtSetReportMode and defines it to be a no-op.
182 * We ifdef it off to avoid warnings about unused variables
184 oldReportMode = _CrtSetReportMode(_CRT_ASSERT, 0);
185 # endif // __MINGW32__
186 # endif // XP_WIN
188 result = strftime(buf, buflen, fmt, &a);
190 # ifdef XP_WIN
191 _set_invalid_parameter_handler(oldHandler);
192 # ifndef __MINGW32__
193 _CrtSetReportMode(_CRT_ASSERT, oldReportMode);
194 # endif // __MINGW32__
195 # endif // XP_WIN
197 if (fake_tm_year && result) {
198 char real_year[16];
199 char fake_year[16];
200 size_t real_year_len;
201 size_t fake_year_len;
202 char* p;
204 sprintf(real_year, "%d", prtm->tm_year);
205 real_year_len = strlen(real_year);
206 sprintf(fake_year, "%d", fake_tm_year);
207 fake_year_len = strlen(fake_year);
209 /* Replace the fake year in the result with the real year. */
210 for (p = buf; (p = strstr(p, fake_year)); p += real_year_len) {
211 size_t new_result = result + real_year_len - fake_year_len;
212 if (new_result >= buflen) {
213 return 0;
215 memmove(p + real_year_len, p + fake_year_len, strlen(p + fake_year_len));
216 memcpy(p, real_year, real_year_len);
217 result = new_result;
218 *(buf + result) = '\0';
221 # endif
222 return result;
224 #endif /* !JS_HAS_INTL_API */