@@ -172,10 +172,11 @@ public TimeSpan[] GetAmbiguousTimeOffsets(DateTimeOffset dateTimeOffset)
172
172
DateTime adjustedTime = ConvertTime ( dateTimeOffset , this ) . DateTime ;
173
173
174
174
bool isAmbiguous = false ;
175
- AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets ( adjustedTime ) ;
175
+ int ? ruleIndex ;
176
+ AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets ( adjustedTime , out ruleIndex ) ;
176
177
if ( rule != null && rule . HasDaylightSaving )
177
178
{
178
- DaylightTimeStruct daylightTime = GetDaylightTime ( adjustedTime . Year , rule ) ;
179
+ DaylightTimeStruct daylightTime = GetDaylightTime ( adjustedTime . Year , rule , ruleIndex ) ;
179
180
isAmbiguous = GetIsAmbiguousTime ( adjustedTime , rule , daylightTime ) ;
180
181
}
181
182
@@ -232,10 +233,11 @@ public TimeSpan[] GetAmbiguousTimeOffsets(DateTime dateTime)
232
233
}
233
234
234
235
bool isAmbiguous = false ;
235
- AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets ( adjustedTime ) ;
236
+ int ? ruleIndex ;
237
+ AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets ( adjustedTime , out ruleIndex ) ;
236
238
if ( rule != null && rule . HasDaylightSaving )
237
239
{
238
- DaylightTimeStruct daylightTime = GetDaylightTime ( adjustedTime . Year , rule ) ;
240
+ DaylightTimeStruct daylightTime = GetDaylightTime ( adjustedTime . Year , rule , ruleIndex ) ;
239
241
isAmbiguous = GetIsAmbiguousTime ( adjustedTime , rule , daylightTime ) ;
240
242
}
241
243
@@ -263,15 +265,15 @@ public TimeSpan[] GetAmbiguousTimeOffsets(DateTime dateTime)
263
265
}
264
266
265
267
// note the time is already adjusted
266
- private AdjustmentRule GetAdjustmentRuleForAmbiguousOffsets ( DateTime adjustedTime )
268
+ private AdjustmentRule GetAdjustmentRuleForAmbiguousOffsets ( DateTime adjustedTime , out int ? ruleIndex )
267
269
{
268
- AdjustmentRule rule = GetAdjustmentRuleForTime ( adjustedTime ) ;
270
+ AdjustmentRule rule = GetAdjustmentRuleForTime ( adjustedTime , out ruleIndex ) ;
269
271
if ( rule != null && rule . NoDaylightTransitions && ! rule . HasDaylightSaving )
270
272
{
271
273
// When using NoDaylightTransitions rules, each rule is only for one offset.
272
274
// When looking for the Daylight savings rules, and we found the non-DST rule,
273
275
// then we get the rule right before this rule.
274
- return GetPreviousAdjustmentRule ( rule ) ;
276
+ return GetPreviousAdjustmentRule ( rule , ruleIndex ) ;
275
277
}
276
278
277
279
return rule ;
@@ -282,10 +284,15 @@ private AdjustmentRule GetAdjustmentRuleForAmbiguousOffsets(DateTime adjustedTim
282
284
/// If the specified rule is the first AdjustmentRule, or it isn't in _adjustmentRules,
283
285
/// then the specified rule is returned.
284
286
/// </summary>
285
- private AdjustmentRule GetPreviousAdjustmentRule ( AdjustmentRule rule )
287
+ private AdjustmentRule GetPreviousAdjustmentRule ( AdjustmentRule rule , int ? ruleIndex )
286
288
{
287
289
Debug . Assert ( rule . NoDaylightTransitions , "GetPreviousAdjustmentRule should only be used with NoDaylightTransitions rules." ) ;
288
290
291
+ if ( ruleIndex . HasValue && 0 < ruleIndex . Value && ruleIndex . Value < _adjustmentRules . Length )
292
+ {
293
+ return _adjustmentRules [ ruleIndex . Value - 1 ] ;
294
+ }
295
+
289
296
AdjustmentRule result = rule ;
290
297
for ( int i = 1 ; i < _adjustmentRules . Length ; i ++ )
291
298
{
@@ -413,10 +420,11 @@ internal bool IsAmbiguousTime(DateTime dateTime, TimeZoneInfoOptions flags)
413
420
dateTime . Kind == DateTimeKind . Utc ? ConvertTime ( dateTime , s_utcTimeZone , this , flags , cachedData ) :
414
421
dateTime ;
415
422
416
- AdjustmentRule rule = GetAdjustmentRuleForTime ( adjustedTime ) ;
423
+ int ? ruleIndex ;
424
+ AdjustmentRule rule = GetAdjustmentRuleForTime ( adjustedTime , out ruleIndex ) ;
417
425
if ( rule != null && rule . HasDaylightSaving )
418
426
{
419
- DaylightTimeStruct daylightTime = GetDaylightTime ( adjustedTime . Year , rule ) ;
427
+ DaylightTimeStruct daylightTime = GetDaylightTime ( adjustedTime . Year , rule , ruleIndex ) ;
420
428
return GetIsAmbiguousTime ( adjustedTime , rule , daylightTime ) ;
421
429
}
422
430
return false ;
@@ -498,10 +506,11 @@ private bool IsDaylightSavingTime(DateTime dateTime, TimeZoneInfoOptions flags,
498
506
//
499
507
// handle the normal cases...
500
508
//
501
- AdjustmentRule rule = GetAdjustmentRuleForTime ( adjustedTime ) ;
509
+ int ? ruleIndex ;
510
+ AdjustmentRule rule = GetAdjustmentRuleForTime ( adjustedTime , out ruleIndex ) ;
502
511
if ( rule != null && rule . HasDaylightSaving )
503
512
{
504
- DaylightTimeStruct daylightTime = GetDaylightTime ( adjustedTime . Year , rule ) ;
513
+ DaylightTimeStruct daylightTime = GetDaylightTime ( adjustedTime . Year , rule , ruleIndex ) ;
505
514
return GetIsDaylightSavings ( adjustedTime , rule , daylightTime , flags ) ;
506
515
}
507
516
else
@@ -521,11 +530,12 @@ public bool IsInvalidTime(DateTime dateTime)
521
530
( dateTime . Kind == DateTimeKind . Local && s_cachedData . GetCorrespondingKind ( this ) == DateTimeKind . Local ) )
522
531
{
523
532
// only check Unspecified and (Local when this TimeZoneInfo instance is Local)
524
- AdjustmentRule rule = GetAdjustmentRuleForTime ( dateTime ) ;
533
+ int ? ruleIndex ;
534
+ AdjustmentRule rule = GetAdjustmentRuleForTime ( dateTime , out ruleIndex ) ;
525
535
526
536
if ( rule != null && rule . HasDaylightSaving )
527
537
{
528
- DaylightTimeStruct daylightTime = GetDaylightTime ( dateTime . Year , rule ) ;
538
+ DaylightTimeStruct daylightTime = GetDaylightTime ( dateTime . Year , rule , ruleIndex ) ;
529
539
isInvalid = GetIsInvalidTime ( dateTime , rule , daylightTime ) ;
530
540
}
531
541
else
@@ -667,7 +677,8 @@ private static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZo
667
677
// performance for the normal case at the expense of the 'ArgumentException'
668
678
// case and Loss-less Local special cases.
669
679
//
670
- AdjustmentRule sourceRule = sourceTimeZone . GetAdjustmentRuleForTime ( dateTime ) ;
680
+ int ? sourceRuleIndex ;
681
+ AdjustmentRule sourceRule = sourceTimeZone . GetAdjustmentRuleForTime ( dateTime , out sourceRuleIndex ) ;
671
682
TimeSpan sourceOffset = sourceTimeZone . BaseUtcOffset ;
672
683
673
684
if ( sourceRule != null )
@@ -676,7 +687,7 @@ private static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZo
676
687
if ( sourceRule . HasDaylightSaving )
677
688
{
678
689
bool sourceIsDaylightSavings = false ;
679
- DaylightTimeStruct sourceDaylightTime = sourceTimeZone . GetDaylightTime ( dateTime . Year , sourceRule ) ;
690
+ DaylightTimeStruct sourceDaylightTime = sourceTimeZone . GetDaylightTime ( dateTime . Year , sourceRule , sourceRuleIndex ) ;
680
691
681
692
// 'dateTime' might be in an invalid time range since it is in an AdjustmentRule
682
693
// period that supports DST
@@ -1054,10 +1065,16 @@ private TimeZoneInfo(SerializationInfo info, StreamingContext context)
1054
1065
_supportsDaylightSavingTime = ( bool ) info . GetValue ( "SupportsDaylightSavingTime" , typeof ( bool ) ) ;
1055
1066
}
1056
1067
1057
- private AdjustmentRule GetAdjustmentRuleForTime ( DateTime dateTime , bool dateTimeisUtc = false )
1068
+ private AdjustmentRule GetAdjustmentRuleForTime ( DateTime dateTime , out int ? ruleIndex )
1069
+ {
1070
+ return GetAdjustmentRuleForTime ( dateTime , dateTimeisUtc : false , ruleIndex : out ruleIndex ) ;
1071
+ }
1072
+
1073
+ private AdjustmentRule GetAdjustmentRuleForTime ( DateTime dateTime , bool dateTimeisUtc , out int ? ruleIndex )
1058
1074
{
1059
1075
if ( _adjustmentRules == null || _adjustmentRules . Length == 0 )
1060
1076
{
1077
+ ruleIndex = null ;
1061
1078
return null ;
1062
1079
}
1063
1080
@@ -1082,6 +1099,7 @@ private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, bool dateTime
1082
1099
int compareResult = CompareAdjustmentRuleToDateTime ( rule , previousRule , dateTime , date , dateTimeisUtc ) ;
1083
1100
if ( compareResult == 0 )
1084
1101
{
1102
+ ruleIndex = median ;
1085
1103
return rule ;
1086
1104
}
1087
1105
else if ( compareResult < 0 )
@@ -1094,6 +1112,7 @@ private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, bool dateTime
1094
1112
}
1095
1113
}
1096
1114
1115
+ ruleIndex = null ;
1097
1116
return null ;
1098
1117
}
1099
1118
@@ -1205,7 +1224,7 @@ private static DateTime ConvertUtcToTimeZone(long ticks, TimeZoneInfo destinatio
1205
1224
/// <summary>
1206
1225
/// Helper function that returns a DaylightTime from a year and AdjustmentRule.
1207
1226
/// </summary>
1208
- private DaylightTimeStruct GetDaylightTime ( int year , AdjustmentRule rule )
1227
+ private DaylightTimeStruct GetDaylightTime ( int year , AdjustmentRule rule , int ? ruleIndex )
1209
1228
{
1210
1229
TimeSpan delta = rule . DaylightDelta ;
1211
1230
DateTime startTime ;
@@ -1217,7 +1236,7 @@ private DaylightTimeStruct GetDaylightTime(int year, AdjustmentRule rule)
1217
1236
// Convert the UTC times into adjusted time zone times.
1218
1237
1219
1238
// use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule
1220
- AdjustmentRule previousRule = GetPreviousAdjustmentRule ( rule ) ;
1239
+ AdjustmentRule previousRule = GetPreviousAdjustmentRule ( rule , ruleIndex ) ;
1221
1240
startTime = ConvertFromUtc ( rule . DateStart , previousRule . DaylightDelta , previousRule . BaseUtcOffsetDelta ) ;
1222
1241
1223
1242
endTime = ConvertFromUtc ( rule . DateEnd , rule . DaylightDelta , rule . BaseUtcOffsetDelta ) ;
@@ -1307,12 +1326,12 @@ private static bool GetIsDaylightSavings(DateTime time, AdjustmentRule rule, Day
1307
1326
/// <summary>
1308
1327
/// Gets the offset that should be used to calculate DST start times from a UTC time.
1309
1328
/// </summary>
1310
- private TimeSpan GetDaylightSavingsStartOffsetFromUtc ( TimeSpan baseUtcOffset , AdjustmentRule rule )
1329
+ private TimeSpan GetDaylightSavingsStartOffsetFromUtc ( TimeSpan baseUtcOffset , AdjustmentRule rule , int ? ruleIndex )
1311
1330
{
1312
1331
if ( rule . NoDaylightTransitions )
1313
1332
{
1314
1333
// use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule
1315
- AdjustmentRule previousRule = GetPreviousAdjustmentRule ( rule ) ;
1334
+ AdjustmentRule previousRule = GetPreviousAdjustmentRule ( rule , ruleIndex ) ;
1316
1335
return baseUtcOffset + previousRule . BaseUtcOffsetDelta + previousRule . DaylightDelta ;
1317
1336
}
1318
1337
else
@@ -1334,7 +1353,7 @@ private TimeSpan GetDaylightSavingsEndOffsetFromUtc(TimeSpan baseUtcOffset, Adju
1334
1353
/// Helper function that checks if a given dateTime is in Daylight Saving Time (DST).
1335
1354
/// This function assumes the dateTime is in UTC and AdjustmentRule is in a different time zone.
1336
1355
/// </summary>
1337
- private static bool GetIsDaylightSavingsFromUtc ( DateTime time , int year , TimeSpan utc , AdjustmentRule rule , out bool isAmbiguousLocalDst , TimeZoneInfo zone )
1356
+ private static bool GetIsDaylightSavingsFromUtc ( DateTime time , int year , TimeSpan utc , AdjustmentRule rule , int ? ruleIndex , out bool isAmbiguousLocalDst , TimeZoneInfo zone )
1338
1357
{
1339
1358
isAmbiguousLocalDst = false ;
1340
1359
@@ -1344,7 +1363,7 @@ private static bool GetIsDaylightSavingsFromUtc(DateTime time, int year, TimeSpa
1344
1363
}
1345
1364
1346
1365
// Get the daylight changes for the year of the specified time.
1347
- DaylightTimeStruct daylightTime = zone . GetDaylightTime ( year , rule ) ;
1366
+ DaylightTimeStruct daylightTime = zone . GetDaylightTime ( year , rule , ruleIndex ) ;
1348
1367
1349
1368
// The start and end times represent the range of universal times that are in DST for that year.
1350
1369
// Within that there is an ambiguous hour, usually right at the end, but at the beginning in
@@ -1358,14 +1377,20 @@ private static bool GetIsDaylightSavingsFromUtc(DateTime time, int year, TimeSpa
1358
1377
// Note we handle the similar case when rule year start with daylight saving and previous year end with daylight saving.
1359
1378
1360
1379
bool ignoreYearAdjustment = false ;
1361
- TimeSpan dstStartOffset = zone . GetDaylightSavingsStartOffsetFromUtc ( utc , rule ) ;
1380
+ TimeSpan dstStartOffset = zone . GetDaylightSavingsStartOffsetFromUtc ( utc , rule , ruleIndex ) ;
1362
1381
DateTime startTime ;
1363
1382
if ( rule . IsStartDateMarkerForBeginningOfYear ( ) && daylightTime . Start . Year > DateTime . MinValue . Year )
1364
1383
{
1365
- AdjustmentRule previousYearRule = zone . GetAdjustmentRuleForTime ( new DateTime ( daylightTime . Start . Year - 1 , 12 , 31 ) ) ;
1384
+ int ? previousYearRuleIndex ;
1385
+ AdjustmentRule previousYearRule = zone . GetAdjustmentRuleForTime (
1386
+ new DateTime ( daylightTime . Start . Year - 1 , 12 , 31 ) ,
1387
+ out previousYearRuleIndex ) ;
1366
1388
if ( previousYearRule != null && previousYearRule . IsEndDateMarkerForEndOfYear ( ) )
1367
1389
{
1368
- DaylightTimeStruct previousDaylightTime = zone . GetDaylightTime ( daylightTime . Start . Year - 1 , previousYearRule ) ;
1390
+ DaylightTimeStruct previousDaylightTime = zone . GetDaylightTime (
1391
+ daylightTime . Start . Year - 1 ,
1392
+ previousYearRule ,
1393
+ previousYearRuleIndex ) ;
1369
1394
startTime = previousDaylightTime . Start - utc - previousYearRule . BaseUtcOffsetDelta ;
1370
1395
ignoreYearAdjustment = true ;
1371
1396
}
@@ -1383,7 +1408,10 @@ private static bool GetIsDaylightSavingsFromUtc(DateTime time, int year, TimeSpa
1383
1408
DateTime endTime ;
1384
1409
if ( rule . IsEndDateMarkerForEndOfYear ( ) && daylightTime . End . Year < DateTime . MaxValue . Year )
1385
1410
{
1386
- AdjustmentRule nextYearRule = zone . GetAdjustmentRuleForTime ( new DateTime ( daylightTime . End . Year + 1 , 1 , 1 ) ) ;
1411
+ int ? nextYearRuleIndex ;
1412
+ AdjustmentRule nextYearRule = zone . GetAdjustmentRuleForTime (
1413
+ new DateTime ( daylightTime . End . Year + 1 , 1 , 1 ) ,
1414
+ out nextYearRuleIndex ) ;
1387
1415
if ( nextYearRule != null && nextYearRule . IsStartDateMarkerForBeginningOfYear ( ) )
1388
1416
{
1389
1417
if ( nextYearRule . IsEndDateMarkerForEndOfYear ( ) )
@@ -1393,7 +1421,10 @@ private static bool GetIsDaylightSavingsFromUtc(DateTime time, int year, TimeSpa
1393
1421
}
1394
1422
else
1395
1423
{
1396
- DaylightTimeStruct nextdaylightTime = zone . GetDaylightTime ( daylightTime . End . Year + 1 , nextYearRule ) ;
1424
+ DaylightTimeStruct nextdaylightTime = zone . GetDaylightTime (
1425
+ daylightTime . End . Year + 1 ,
1426
+ nextYearRule ,
1427
+ nextYearRuleIndex ) ;
1397
1428
endTime = nextdaylightTime . End - utc - nextYearRule . BaseUtcOffsetDelta - nextYearRule . DaylightDelta ;
1398
1429
}
1399
1430
ignoreYearAdjustment = true ;
@@ -1650,14 +1681,15 @@ private static bool GetIsInvalidTime(DateTime time, AdjustmentRule rule, Dayligh
1650
1681
private static TimeSpan GetUtcOffset ( DateTime time , TimeZoneInfo zone , TimeZoneInfoOptions flags )
1651
1682
{
1652
1683
TimeSpan baseOffset = zone . BaseUtcOffset ;
1653
- AdjustmentRule rule = zone . GetAdjustmentRuleForTime ( time ) ;
1684
+ int ? ruleIndex ;
1685
+ AdjustmentRule rule = zone . GetAdjustmentRuleForTime ( time , out ruleIndex ) ;
1654
1686
1655
1687
if ( rule != null )
1656
1688
{
1657
1689
baseOffset = baseOffset + rule . BaseUtcOffsetDelta ;
1658
1690
if ( rule . HasDaylightSaving )
1659
1691
{
1660
- DaylightTimeStruct daylightTime = zone . GetDaylightTime ( time . Year , rule ) ;
1692
+ DaylightTimeStruct daylightTime = zone . GetDaylightTime ( time . Year , rule , ruleIndex ) ;
1661
1693
bool isDaylightSavings = GetIsDaylightSavings ( time , rule , daylightTime , flags ) ;
1662
1694
baseOffset += ( isDaylightSavings ? rule . DaylightDelta : TimeSpan . Zero /* FUTURE: rule.StandardDelta */ ) ;
1663
1695
}
@@ -1696,21 +1728,22 @@ internal static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone, o
1696
1728
isAmbiguousLocalDst = false ;
1697
1729
TimeSpan baseOffset = zone . BaseUtcOffset ;
1698
1730
int year ;
1731
+ int ? ruleIndex ;
1699
1732
AdjustmentRule rule ;
1700
1733
1701
1734
if ( time > s_maxDateOnly )
1702
1735
{
1703
- rule = zone . GetAdjustmentRuleForTime ( DateTime . MaxValue ) ;
1736
+ rule = zone . GetAdjustmentRuleForTime ( DateTime . MaxValue , out ruleIndex ) ;
1704
1737
year = 9999 ;
1705
1738
}
1706
1739
else if ( time < s_minDateOnly )
1707
1740
{
1708
- rule = zone . GetAdjustmentRuleForTime ( DateTime . MinValue ) ;
1741
+ rule = zone . GetAdjustmentRuleForTime ( DateTime . MinValue , out ruleIndex ) ;
1709
1742
year = 1 ;
1710
1743
}
1711
1744
else
1712
1745
{
1713
- rule = zone . GetAdjustmentRuleForTime ( time , dateTimeisUtc : true ) ;
1746
+ rule = zone . GetAdjustmentRuleForTime ( time , dateTimeisUtc : true , ruleIndex : out ruleIndex ) ;
1714
1747
1715
1748
// As we get the associated rule using the adjusted targetTime, we should use the adjusted year (targetTime.Year) too as after adding the baseOffset,
1716
1749
// sometimes the year value can change if the input datetime was very close to the beginning or the end of the year. Examples of such cases:
@@ -1725,7 +1758,7 @@ internal static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone, o
1725
1758
baseOffset = baseOffset + rule . BaseUtcOffsetDelta ;
1726
1759
if ( rule . HasDaylightSaving )
1727
1760
{
1728
- isDaylightSavings = GetIsDaylightSavingsFromUtc ( time , year , zone . _baseUtcOffset , rule , out isAmbiguousLocalDst , zone ) ;
1761
+ isDaylightSavings = GetIsDaylightSavingsFromUtc ( time , year , zone . _baseUtcOffset , rule , ruleIndex , out isAmbiguousLocalDst , zone ) ;
1729
1762
baseOffset += ( isDaylightSavings ? rule . DaylightDelta : TimeSpan . Zero /* FUTURE: rule.StandardDelta */ ) ;
1730
1763
}
1731
1764
}
0 commit comments