Skip to content

Commit def4264

Browse files
committed
initial test checkin
Additional Test Basic Tests Pass add time conversion tests all test pass cleanup change from int* to MonoBoolean* Match mono code conventions cleanup classlib changes Use mono format for tests add test for singapore, as this is a timezone that tripped us up in the past
1 parent 839ec21 commit def4264

File tree

5 files changed

+497
-111
lines changed

5 files changed

+497
-111
lines changed

mcs/class/corlib/System/TimeZone.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public override bool IsDaylightSavingTime (DateTime dateTime)
221221
// name[1]: name of this timezone when daylight saving.
222222
#if UNITY
223223
[MethodImplAttribute(MethodImplOptions.InternalCall)]
224-
public static extern bool GetTimeZoneData (int year, out Int64[] data, out string[] names);
224+
public static extern bool GetTimeZoneData (int year, out Int64[] data, out string[] names, out bool daylight_inverted);
225225
#endif
226226
}
227227
}

mcs/class/corlib/System/TimeZoneInfo.Unity.cs

Lines changed: 88 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ namespace System {
2222
public partial class TimeZoneInfo {
2323
enum TimeZoneData
2424
{
25-
DaylightSavingStartIdx,
26-
DaylightSavingEndIdx,
25+
DaylightSavingFirstTransitionIdx,
26+
DaylightSavingSecondTransitionIdx,
2727
UtcOffsetIdx,
2828
AdditionalDaylightOffsetIdx
2929
};
@@ -34,12 +34,14 @@ enum TimeZoneNames
3434
DaylightNameIdx
3535
};
3636

37-
static AdjustmentRule CreateAdjustmentRule(int year, out Int64[] data, out string[] names, string standardNameCurrentYear, string daylightNameCurrentYear)
37+
static List<AdjustmentRule> CreateAdjustmentRule (int year, out Int64[] data, out string[] names, string standardNameCurrentYear, string daylightNameCurrentYear)
3838
{
39-
if(!System.CurrentSystemTimeZone.GetTimeZoneData(year, out data, out names))
40-
return null;
41-
var startTime = new DateTime (data[(int)TimeZoneData.DaylightSavingStartIdx]);
42-
var endTime = new DateTime (data[(int)TimeZoneData.DaylightSavingEndIdx]);
39+
List<AdjustmentRule> rulesForYear = new List<AdjustmentRule> ();
40+
bool dst_inverted;
41+
if (!System.CurrentSystemTimeZone.GetTimeZoneData(year, out data, out names, out dst_inverted))
42+
return rulesForYear;
43+
var firstTransition = new DateTime (data[(int)TimeZoneData.DaylightSavingFirstTransitionIdx]);
44+
var secondTransition = new DateTime (data[(int)TimeZoneData.DaylightSavingSecondTransitionIdx]);
4345
var daylightOffset = new TimeSpan (data[(int)TimeZoneData.AdditionalDaylightOffsetIdx]);
4446

4547
/* C# TimeZoneInfo does not support timezones the same way as unix. In unix, timezone files are specified by region such as
@@ -48,73 +50,116 @@ static AdjustmentRule CreateAdjustmentRule(int year, out Int64[] data, out strin
4850
* savings time. As such we'll only generate timezone rules for a region at the times associated with the timezone of the current year.
4951
*/
5052
if(standardNameCurrentYear != names[(int)TimeZoneNames.StandardNameIdx])
51-
return null;
53+
return rulesForYear;
5254
if(daylightNameCurrentYear != names[(int)TimeZoneNames.DaylightNameIdx])
53-
return null;
54-
55-
var dlsTransitionStart = TransitionTime.CreateFixedDateRule(new DateTime(1,1,1).Add(startTime.TimeOfDay),
56-
startTime.Month, startTime.Day);
57-
var dlsTransitionEnd = TransitionTime.CreateFixedDateRule(new DateTime(1,1,1).Add(endTime.TimeOfDay),
58-
endTime.Month, endTime.Day);
59-
60-
var rule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(year, 1, 1),
61-
new DateTime(year, 12, DateTime.DaysInMonth(year, 12)),
62-
daylightOffset,
63-
dlsTransitionStart,
64-
dlsTransitionEnd);
65-
return rule;
55+
return rulesForYear;
56+
57+
var beginningOfYear = new DateTime (year, 1, 1, 0, 0, 0, 0);
58+
var endOfYearDay = new DateTime (year, 12, DateTime.DaysInMonth (year, 12));
59+
var endOfYearMaxTimeout = new DateTime (year, 12, DateTime.DaysInMonth(year, 12), 23, 59, 59, 999);
60+
61+
if (!dst_inverted) {
62+
// For daylight savings time that happens between jan and dec, create a rule from jan 1 to dec 31 (the entire year)
63+
64+
// This rule (for the whole year) specifies the starting and ending months of daylight savings time.
65+
var startOfDaylightSavingsTime = TransitionTime.CreateFixedDateRule (new DateTime (1,1,1).Add (firstTransition.TimeOfDay),
66+
firstTransition.Month, firstTransition.Day);
67+
var endOfDaylightSavingsTime = TransitionTime.CreateFixedDateRule (new DateTime (1,1,1).Add (secondTransition.TimeOfDay),
68+
secondTransition.Month, secondTransition.Day);
69+
70+
var fullYearRule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (beginningOfYear,
71+
endOfYearDay,
72+
daylightOffset,
73+
startOfDaylightSavingsTime,
74+
endOfDaylightSavingsTime);
75+
rulesForYear.Add (fullYearRule);
76+
} else {
77+
// Some timezones (Australia/Sydney) have daylight savings over the new year.
78+
// Our icall returns the transitions for the current year, so we need two adjustment rules each year for this case
79+
80+
// The first rule specifies daylight savings starting at jan 1 and ending at the first transition.
81+
var startOfFirstDaylightSavingsTime = TransitionTime.CreateFixedDateRule (new DateTime (1,1,1), 1, 1);
82+
var endOfFirstDaylightSavingsTime = TransitionTime.CreateFixedDateRule (new DateTime (1,1,1).Add (firstTransition.TimeOfDay),
83+
firstTransition.Month, firstTransition.Day);
84+
85+
var transitionOutOfDaylightSavingsRule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (
86+
new DateTime (year, 1, 1),
87+
new DateTime (firstTransition.Year, firstTransition.Month, firstTransition.Day),
88+
daylightOffset,
89+
startOfFirstDaylightSavingsTime,
90+
endOfFirstDaylightSavingsTime);
91+
rulesForYear.Add (transitionOutOfDaylightSavingsRule);
92+
93+
// The second rule specifies daylight savings time starting the day after we transition out of daylight savings
94+
// and ending at the end of the year, with daylight savings starting near the end and ending on the last day of the year
95+
var startOfSecondDaylightSavingsTime = TransitionTime.CreateFixedDateRule (new DateTime (1,1,1).Add (secondTransition.TimeOfDay),
96+
secondTransition.Month, secondTransition.Day);
97+
var endOfSecondDaylightSavingsTime = TransitionTime.CreateFixedDateRule (new DateTime (1,1,1).Add (endOfYearMaxTimeout.TimeOfDay),
98+
endOfYearMaxTimeout.Month, endOfYearMaxTimeout.Day);
99+
100+
var transitionIntoDaylightSavingsRule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (
101+
new DateTime (firstTransition.Year, firstTransition.Month, firstTransition.Day).AddDays (1),
102+
endOfYearDay,
103+
daylightOffset,
104+
startOfSecondDaylightSavingsTime,
105+
endOfSecondDaylightSavingsTime);
106+
rulesForYear.Add (transitionIntoDaylightSavingsRule);
107+
}
108+
return rulesForYear;
66109
}
67110

68111
static TimeZoneInfo CreateLocalUnity ()
69112
{
70113
Int64[] data;
71114
string[] names;
115+
//Some timezones start in DST on january first and disable it during the summer
116+
bool dst_inverted;
72117
int currentYear = DateTime.UtcNow.Year;
73-
if (!System.CurrentSystemTimeZone.GetTimeZoneData (currentYear, out data, out names))
118+
if (!System.CurrentSystemTimeZone.GetTimeZoneData (currentYear, out data, out names, out dst_inverted))
74119
throw new NotSupportedException ("Can't get timezone name.");
75120

76-
var utcOffsetTS = TimeSpan.FromTicks(data[(int)TimeZoneData.UtcOffsetIdx]);
121+
var utcOffsetTS = TimeSpan.FromTicks (data[(int)TimeZoneData.UtcOffsetIdx]);
77122
char utcOffsetSign = (utcOffsetTS >= TimeSpan.Zero) ? '+' : '-';
78-
string displayName = "(GMT" + utcOffsetSign + utcOffsetTS.ToString(@"hh\:mm") + ") Local Time";
123+
string displayName = "(GMT" + utcOffsetSign + utcOffsetTS.ToString (@"hh\:mm") + ") Local Time";
79124
string standardDisplayName = names[(int)TimeZoneNames.StandardNameIdx];
80125
string daylightDisplayName = names[(int)TimeZoneNames.DaylightNameIdx];
81126

82-
var adjustmentList = new List<AdjustmentRule>();
83-
bool disableDaylightSavings = data[(int)TimeZoneData.AdditionalDaylightOffsetIdx] <= 0;
127+
var adjustmentRulesList = new List<AdjustmentRule> ();
128+
bool disableDaylightSavings = data[(int)TimeZoneData.AdditionalDaylightOffsetIdx] == 0;
84129
//If the timezone supports daylight savings time, generate adjustment rules for the timezone
85-
if(!disableDaylightSavings)
86-
{
130+
if (!disableDaylightSavings) {
87131
//the icall only supports years from 1970 through 2037.
88132
int firstSupportedDate = 1971;
89133
int lastSupportedDate = 2037;
90134

91135
//first, generate rules from the current year until the last year mktime is guaranteed to supports
92-
for(int year = currentYear; year <= lastSupportedDate; year++)
93-
{
94-
var rule = CreateAdjustmentRule(year, out data, out names, standardDisplayName, daylightDisplayName);
95-
//breakout if timezone changes, or fails
96-
if(rule == null)
136+
for (int year = currentYear; year <= lastSupportedDate; year++) {
137+
var rulesForCurrentYear = CreateAdjustmentRule (year, out data, out names, standardDisplayName, daylightDisplayName);
138+
//breakout if no more rules
139+
if (rulesForCurrentYear.Count > 0)
140+
adjustmentRulesList.AddRange (rulesForCurrentYear);
141+
else
97142
break;
98-
adjustmentList.Add(rule);
143+
99144
}
100145

101-
for(int year = currentYear - 1; year >= firstSupportedDate; year--)
102-
{
103-
var rule = CreateAdjustmentRule(year, out data, out names, standardDisplayName, daylightDisplayName);
104-
//breakout if timezone changes, or fails
105-
if(rule == null)
146+
for (int year = currentYear - 1; year >= firstSupportedDate; year--) {
147+
var rulesForCurrentYear = CreateAdjustmentRule (year, out data, out names, standardDisplayName, daylightDisplayName);
148+
//breakout if no more rules
149+
if (rulesForCurrentYear.Count > 0)
150+
adjustmentRulesList.AddRange (rulesForCurrentYear);
151+
else
106152
break;
107-
adjustmentList.Add(rule);
108153
}
109154

110-
adjustmentList.Sort( (rule1, rule2) => rule1.DateStart.CompareTo(rule2.DateStart) );
155+
adjustmentRulesList.Sort ( (rule1, rule2) => rule1.DateStart.CompareTo (rule2.DateStart) );
111156
}
112-
return TimeZoneInfo.CreateCustomTimeZone("Local",
157+
return TimeZoneInfo.CreateCustomTimeZone ("Local",
113158
utcOffsetTS,
114159
displayName,
115160
standardDisplayName,
116161
daylightDisplayName,
117-
adjustmentList.ToArray(),
162+
adjustmentRulesList.ToArray (),
118163
disableDaylightSavings);
119164
}
120165
}

0 commit comments

Comments
 (0)