Skip to content

Commit

Permalink
Timedate icu fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Fedor committed May 4, 2024
1 parent 5098993 commit e7eb1bb
Show file tree
Hide file tree
Showing 6 changed files with 661 additions and 46 deletions.
116 changes: 70 additions & 46 deletions intl/icu/source/common/wintz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ uprv_detectWindowsTimeZone()
TZI tziReg;
TIME_ZONE_INFORMATION apiTZI;

BOOL isVistaOrHigher;
BOOL tryPreVistaFallback;
OSVERSIONINFO osVerInfo;

Expand All @@ -252,9 +253,10 @@ uprv_detectWindowsTimeZone()
tmpid[0] = 0;

id = GetUserGeoID(GEOCLASS_NATION);
errorCode = GetGeoInfoW(id, GEO_ISO2, ISOcodeW, 3, 0);
u_strToUTF8(ISOcodeA, 3, NULL, (const UChar *)ISOcodeW, 3, &status);
errorCode = GetGeoInfoW(id, GEO_ISO2, ISOcodeW, sizeof(ISOcodeW), 0);
u_strToUTF8(ISOcodeA, sizeof(ISOcodeA), NULL, (const UChar *)ISOcodeW, sizeof(ISOcodeW), &status);

status = U_ZERO_ERROR;
bundle = ures_openDirect(NULL, "windowsZones", &status);
ures_getByKey(bundle, "mapTimezones", bundle, &status);

Expand All @@ -265,53 +267,83 @@ uprv_detectWindowsTimeZone()
*/
uprv_memset(&osVerInfo, 0, sizeof(osVerInfo));
osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo);
isVistaOrHigher = osVerInfo.dwMajorVersion >= 6;

tryPreVistaFallback = TRUE;
result = getTZKeyName(regStdName, sizeof(regStdName));
if(ERROR_SUCCESS == result)
{
UResourceBundle* winTZ = ures_getByKey(bundle, regStdName, NULL, &status);
if(U_SUCCESS(status))
{
const UChar* icuTZ = NULL;
if (errorCode != 0)
{
icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &status);
}
if (errorCode==0 || icuTZ==NULL)
{
/* fallback to default "001" and reset status */
status = U_ZERO_ERROR;
icuTZ = ures_getStringByKey(winTZ, "001", &len, &status);
}

if(isVistaOrHigher) {
result = getTZKeyName(regStdName, sizeof(regStdName));
if(ERROR_SUCCESS == result)
{
UResourceBundle* winTZ = ures_getByKey(bundle, regStdName, NULL, &status);
if(U_SUCCESS(status))
{
int index=0;
while (! (*icuTZ == '\0' || *icuTZ ==' '))
const UChar* icuTZ = NULL;
if (errorCode != 0)
{
icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &status);
}
if (errorCode==0 || icuTZ==NULL)
{
tmpid[index++]=(char)(*icuTZ++); /* safe to assume 'char' is ASCII compatible on windows */
/* fallback to default "001" and reset status */
status = U_ZERO_ERROR;
icuTZ = ures_getStringByKey(winTZ, "001", &len, &status);
}

if(U_SUCCESS(status))
{
int index=0;
while (! (*icuTZ == '\0' || *icuTZ ==' '))
{
tmpid[index++]=(char)(*icuTZ++); /* safe to assume 'char' is ASCII compatible on windows */
}
tmpid[index]='\0';
tryPreVistaFallback = FALSE;
}
tmpid[index]='\0';
tryPreVistaFallback = FALSE;
}
ures_close(winTZ);
}
ures_close(winTZ);
}

if(tryPreVistaFallback)
{
/* Note: We get the winid not from static tables but from resource bundle. */
while (U_SUCCESS(status) && ures_hasNext(bundle))
HKEY hZonesKey;
DWORD dwIndex;
DWORD dwNameSize;
CHAR szKeyName[MAX_LENGTH_ID];
CHAR tmp[256];
UBool idFound = FALSE;

/* Open the registry key containing the list of time zones */
result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
TZ_REGKEY,
0,
KEY_ENUMERATE_SUB_KEYS,
&hZonesKey);
if (result != ERROR_SUCCESS)
{
return icuid;
}

/* Enumerate it */
for (dwIndex = 0;; dwIndex++)
{
UBool idFound = FALSE;
const char* winid;
UResourceBundle* winTZ = ures_getNextResource(bundle, NULL, &status);
if (U_FAILURE(status))
dwNameSize = sizeof(szKeyName);
result = RegEnumKeyExA(hZonesKey,
dwIndex,
szKeyName,
&dwNameSize,
NULL,
NULL,
NULL,
NULL);
// if (lError != ERROR_SUCCESS && lError != ERROR_MORE_DATA)
if (result == ERROR_NO_MORE_ITEMS)
{
break;
}
winid = ures_getKey(winTZ);
result = getTZI(winid, &tziReg);

result = getTZI(szKeyName, &tziReg);

if (result == ERROR_SUCCESS)
{
Expand All @@ -321,9 +353,10 @@ uprv_detectWindowsTimeZone()
tziKey.standardBias = tziReg.standardBias;
tziKey.daylightBias = tziReg.daylightBias;

if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey)) == 0)
if (uprv_memcmp((char*)&tziKey, (char*)&tziReg, sizeof(tziKey)) == 0)
{
const UChar* icuTZ = NULL;
UResourceBundle* winTZ = ures_getByKey(bundle, szKeyName, NULL, &status);
if (errorCode != 0)
{
icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &status);
Expand All @@ -337,17 +370,7 @@ uprv_detectWindowsTimeZone()

if (U_SUCCESS(status))
{
/* Get the standard name from the registry key to compare with
the one from Windows API call. */
uprv_memset(regStdName, 0, sizeof(regStdName));
result = getSTDName(winid, regStdName, sizeof(regStdName));
if (result == ERROR_SUCCESS)
{
if (uprv_strcmp(apiStdName, regStdName) == 0)
{
idFound = TRUE;
}
}
idFound = TRUE;

/* tmpid buffer holds the ICU timezone ID corresponding to the timezone ID from Windows.
* If none is found, tmpid buffer will contain a fallback ID (i.e. the time zone ID matching
Expand All @@ -364,14 +387,15 @@ uprv_detectWindowsTimeZone()
tmpid[index]='\0';
}
}
ures_close(winTZ);
}
}
ures_close(winTZ);
if (idFound)
{
break;
}
}
RegCloseKey(hZonesKey);
}

/*
Expand Down
94 changes: 94 additions & 0 deletions js/src/jsdate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,25 @@ namespace {

class DateTimeHelper {
private:
#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU
static double localTZA(double t, DateTimeInfo::TimeZoneOffset offset);
#else
static int equivalentYearForDST(int year);
static bool isRepresentableAsTime32(double t);
static double daylightSavingTA(double t);
static double adjustTime(double date);
static PRMJTime toPRMJTime(double localTime, double utcTime);
#endif

public:
static double localTime(double t);
static double UTC(double t);
static JSString* timeZoneComment(JSContext* cx, double utcTime,
double localTime);
#if !JS_HAS_INTL_API || MOZ_SYSTEM_ICU
static size_t formatTime(char* buf, size_t buflen, const char* fmt,
double utcTime, double localTime);
#endif
};

} // namespace
Expand Down Expand Up @@ -435,6 +441,43 @@ JS_PUBLIC_API void JS::SetTimeResolutionUsec(uint32_t resolution, bool jitter) {
sJitter = jitter;
}

#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU
// ES2019 draft rev 0ceb728a1adbffe42b26972a6541fd7f398b1557
// 20.3.1.7 LocalTZA ( t, isUTC )
double DateTimeHelper::localTZA(double t, DateTimeInfo::TimeZoneOffset offset) {
MOZ_ASSERT(IsFinite(t));

int64_t milliseconds = static_cast<int64_t>(t);
int32_t offsetMilliseconds =
DateTimeInfo::getOffsetMilliseconds(milliseconds, offset);
return static_cast<double>(offsetMilliseconds);
}

// ES2019 draft rev 0ceb728a1adbffe42b26972a6541fd7f398b1557
// 20.3.1.8 LocalTime ( t )
double DateTimeHelper::localTime(double t) {
if (!IsFinite(t)) {
return GenericNaN();
}

MOZ_ASSERT(StartOfTime <= t && t <= EndOfTime);
return t + localTZA(t, DateTimeInfo::TimeZoneOffset::UTC);
}

// ES2019 draft rev 0ceb728a1adbffe42b26972a6541fd7f398b1557
// 20.3.1.9 UTC ( t )
double DateTimeHelper::UTC(double t) {
if (!IsFinite(t)) {
return GenericNaN();
}

if (t < (StartOfTime - msPerDay) || t > (EndOfTime + msPerDay)) {
return GenericNaN();
}

return t - localTZA(t, DateTimeInfo::TimeZoneOffset::Local);
}
#else
/*
* Find a year for which any given date will fall on the same weekday.
*
Expand Down Expand Up @@ -520,6 +563,7 @@ double DateTimeHelper::UTC(double t) {

return t - adjustTime(t - DateTimeInfo::localTZA() - msPerHour);
}
#endif /* JS_HAS_INTL_API && !MOZ_SYSTEM_ICU */

static double LocalTime(double t) { return DateTimeHelper::localTime(t); }

Expand Down Expand Up @@ -2643,6 +2687,45 @@ static bool date_toJSON(JSContext* cx, unsigned argc, Value* vp) {
return Call(cx, toISO, obj, args.rval());
}

#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU
JSString* DateTimeHelper::timeZoneComment(JSContext* cx, double utcTime,
double localTime) {
const char* locale = cx->runtime()->getDefaultLocale();
if (!locale) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_DEFAULT_LOCALE_ERROR);
return nullptr;
}

char16_t tzbuf[100];
tzbuf[0] = ' ';
tzbuf[1] = '(';

char16_t* timeZoneStart = tzbuf + 2;
constexpr size_t remainingSpace =
mozilla::ArrayLength(tzbuf) - 2 - 1; // for the trailing ')'

int64_t utcMilliseconds = static_cast<int64_t>(utcTime);
if (!DateTimeInfo::timeZoneDisplayName(timeZoneStart, remainingSpace,
utcMilliseconds, locale)) {
{
JS_ReportOutOfMemory(cx);
}
return nullptr;
}

// Reject if the result string is empty.
size_t len = js_strlen(timeZoneStart);
if (len == 0) {
return cx->names().empty;
}

// Parenthesize the returned display name.
timeZoneStart[len] = ')';

return NewStringCopyN<CanGC>(cx, tzbuf, 2 + len + 1);
}
#else
/* Interface to PRMJTime date struct. */
PRMJTime DateTimeHelper::toPRMJTime(double localTime, double utcTime) {
double year = YearFromTime(localTime);
Expand Down Expand Up @@ -2710,6 +2793,7 @@ JSString* DateTimeHelper::timeZoneComment(JSContext* cx, double utcTime,

return cx->names().empty;
}
#endif /* JS_HAS_INTL_API && !MOZ_SYSTEM_ICU */

static JSString* TimeZoneComment(JSContext* cx, double utcTime,
double localTime) {
Expand Down Expand Up @@ -2811,6 +2895,7 @@ static bool FormatDate(JSContext* cx, double utcTime, FormatSpec format,
return true;
}

#if !JS_HAS_INTL_API
static bool ToLocaleFormatHelper(JSContext* cx, HandleObject obj,
const char* format, MutableHandleValue rval) {
double utcTime = obj->as<DateObject>().UTCTime().toNumber();
Expand Down Expand Up @@ -2918,6 +3003,7 @@ static bool date_toLocaleTimeString(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsDate, date_toLocaleTimeString_impl>(cx, args);
}
#endif /* !JS_HAS_INTL_API */

/* ES5 15.9.5.4. */
MOZ_ALWAYS_INLINE bool date_toTimeString_impl(JSContext* cx,
Expand Down Expand Up @@ -3056,9 +3142,17 @@ static const JSFunctionSpec date_methods[] = {
JS_FN("setMilliseconds", date_setMilliseconds, 1, 0),
JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1, 0),
JS_FN("toUTCString", date_toGMTString, 0, 0),
#if JS_HAS_INTL_API
JS_SELF_HOSTED_FN(js_toLocaleString_str, "Date_toLocaleString", 0, 0),
JS_FN("toLocaleDateString", date_toDateString, 0, 0),
JS_FN("toLocaleTimeString", date_toTimeString, 0, 0),
//JS_SELF_HOSTED_FN("toLocaleDateString", "Date_toLocaleDateString", 0, 0),
//JS_SELF_HOSTED_FN("toLocaleTimeString", "Date_toLocaleTimeString", 0, 0),
#else
JS_FN(js_toLocaleString_str, date_toLocaleString, 0, 0),
JS_FN("toLocaleDateString", date_toLocaleDateString, 0, 0),
JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0, 0),
#endif
JS_FN("toDateString", date_toDateString, 0, 0),
JS_FN("toTimeString", date_toTimeString, 0, 0),
JS_FN("toISOString", date_toISOString, 0, 0),
Expand Down
Loading

0 comments on commit e7eb1bb

Please sign in to comment.