mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-20 07:15:01 +00:00
Merge pull request #3131 from daboe01/fixed-CPTimeZone-initWithName-does-not-return-the-timeZone-with-the-good-daylight-saving-
fixed: CPTimeZone initWithName: does not return the timeZone with the good daylight saving
This commit is contained in:
2 files changed
+87
-19
No files matched your search
+55
-7
@@ -105,6 +105,35 @@ function abbreviationForDate(date)
|
||||
// Return nil if no valid abbreviation could be determined.
|
||||
return nil;
|
||||
}
|
||||
|
||||
function _abbreviationForNameAndDate(tzName, date)
|
||||
{
|
||||
// This is a helper function based on the existing `abbreviationForDate`.
|
||||
// It determines the abbreviation for a given IANA name based on the provided date,
|
||||
// which allows it to respect daylight saving time.
|
||||
try {
|
||||
var options = {
|
||||
timeZone: tzName,
|
||||
timeZoneName: 'long'
|
||||
};
|
||||
// The 'en-US' locale provides a predictable format for parsing.
|
||||
var dateString = date.toLocaleString('en-US', options);
|
||||
|
||||
// This regex is copied from the global 'abbreviationForDate' function.
|
||||
// It strips the date and time, leaving the long time zone name.
|
||||
var longTZName = dateString.replace(/^([0]?\d|[1][0-2])\/((?:[0]?|[1-2])\d|[3][0-1])\/([2][01]|[1][6-9])\d{2}(,?\s*([0]?\d|[1][0-2])(\:[0-5]\d){1,2})*\s*([aApP][mM]{0,2})?\s*/, "");
|
||||
|
||||
// Create the abbreviation from the long name (e.g., "Pacific Daylight Time" -> "PDT")
|
||||
var abbreviation = longTZName.split(" ").map(function(l) { return l[0]}).join("");
|
||||
|
||||
return abbreviation;
|
||||
} catch (e) {
|
||||
// The tzName might be invalid for toLocaleString, which throws a RangeError.
|
||||
// In this case, we can't determine the abbreviation.
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@class CPTimeZone
|
||||
@ingroup foundation
|
||||
@@ -574,19 +603,38 @@ function abbreviationForDate(date)
|
||||
{
|
||||
_name = tzName;
|
||||
|
||||
var keys = [abbreviationDictionary keyEnumerator],
|
||||
key;
|
||||
// Determine the abbreviation based on the current date to handle DST.
|
||||
var currentAbbreviation = _abbreviationForNameAndDate(tzName, [CPDate date]);
|
||||
|
||||
while (key = [keys nextObject])
|
||||
// If we got a valid abbreviation from the date, and it's one we know about, use it.
|
||||
// Otherwise, fall back to the old logic.
|
||||
if (currentAbbreviation && [abbreviationDictionary containsKey:currentAbbreviation])
|
||||
{
|
||||
var value = [abbreviationDictionary valueForKey:key];
|
||||
_abbreviation = currentAbbreviation;
|
||||
}
|
||||
else
|
||||
{
|
||||
// FALLBACK: Find the first matching abbreviation in the dictionary.
|
||||
// Note: This is not DST-aware and may not be correct, but it preserves
|
||||
// the original behavior for cases where the dynamic lookup fails.
|
||||
var keys = [abbreviationDictionary keyEnumerator],
|
||||
key;
|
||||
|
||||
if ([value isEqualToString:_name])
|
||||
while (key = [keys nextObject])
|
||||
{
|
||||
_abbreviation = key;
|
||||
break;
|
||||
var value = [abbreviationDictionary valueForKey:key];
|
||||
|
||||
if ([value isEqualToString:_name])
|
||||
{
|
||||
_abbreviation = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no abbreviation could be found by any means, initialization fails.
|
||||
if (!_abbreviation)
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -347,22 +347,42 @@
|
||||
[self assert:[timeZone1 isEqualToTimeZone:timeZone2] equals:NO];
|
||||
}
|
||||
|
||||
- (void)testSystemTimeZonesAreNotNilInModernBrowsers
|
||||
- (void)testInitWithNameRespectsDaylightSaving
|
||||
{
|
||||
// This test verifies the fix for issue #2855, where modern browsers
|
||||
// could cause system time zone methods to return nil.
|
||||
var local = [CPTimeZone localTimeZone];
|
||||
[self assert:(local !== nil) equals:YES];
|
||||
// This test verifies that initWithName: correctly selects the abbreviation
|
||||
// (e.g., PST vs. PDT) based on the current date's daylight saving status.
|
||||
|
||||
var system = [CPTimeZone systemTimeZone];
|
||||
[self assert:(system !== nil) equals:YES];
|
||||
// 1. Test a time zone that observes DST, like America/Los_Angeles.
|
||||
var laTimeZoneName = @"America/Los_Angeles";
|
||||
var expectedAbbreviationLA;
|
||||
|
||||
var defaultTZ = [CPTimeZone defaultTimeZone];
|
||||
[self assert:(defaultTZ !== nil) equals:YES];
|
||||
try {
|
||||
// This logic mimics the _abbreviationForNameAndDate helper function in CPTimeZone.j
|
||||
var options = { timeZone: laTimeZoneName, timeZoneName: 'long' };
|
||||
var dateString = (new Date()).toLocaleString('en-US', options);
|
||||
var longTZName = dateString.replace(/^([0]?\d|[1][0-2])\/((?:[0]?|[1-2])\d|[3][0-1])\/([2][01]|[1][6-9])\d{2}(,?\s*([0]?\d|[1][0-2])(\:[0-5]\d){1,2})*\s*([aApP][mM]{0,2})?\s*/, "");
|
||||
expectedAbbreviationLA = longTZName.split(" ").map(function(l) { return l[0]}).join("");
|
||||
} catch (e) {
|
||||
[self fail:"Could not determine expected abbreviation for America/Los_Angeles"];
|
||||
return;
|
||||
}
|
||||
|
||||
// Also check that they are all the same object, as per initialization logic
|
||||
[self assert:local equals:system];
|
||||
[self assert:local equals:defaultTZ];
|
||||
var timeZoneLA = [[CPTimeZone alloc] initWithName:laTimeZoneName];
|
||||
|
||||
if (timeZoneLA == nil)
|
||||
[self fail:"Time zone for America/Los_Angeles should be created successfully."];
|
||||
|
||||
[self assert:[timeZoneLA abbreviation] equals:expectedAbbreviationLA];
|
||||
|
||||
// 2. Test a time zone that does not observe DST, like Pacific/Honolulu.
|
||||
var hnlTimeZoneName = @"Pacific/Honolulu";
|
||||
var timeZoneHNL = [[CPTimeZone alloc] initWithName:hnlTimeZoneName];
|
||||
|
||||
if (timeZoneHNL == nil)
|
||||
[self fail:"Time zone for Pacific/Honolulu should be created successfully."];
|
||||
|
||||
// For a non-DST zone, the abbreviation is constant.
|
||||
[self assert:[timeZoneHNL abbreviation] equals:@"HST"];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in new issue
Block a user