1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System
.Runtime
.Serialization
;
9 public sealed partial class TimeZoneInfo
12 public readonly struct TransitionTime
: IEquatable
<TransitionTime
>, ISerializable
, IDeserializationCallback
14 private readonly DateTime _timeOfDay
;
15 private readonly byte _month
;
16 private readonly byte _week
;
17 private readonly byte _day
;
18 private readonly DayOfWeek _dayOfWeek
;
19 private readonly bool _isFixedDateRule
;
21 public DateTime TimeOfDay
=> _timeOfDay
;
23 public int Month
=> _month
;
25 public int Week
=> _week
;
27 public int Day
=> _day
;
29 public DayOfWeek DayOfWeek
=> _dayOfWeek
;
31 public bool IsFixedDateRule
=> _isFixedDateRule
;
33 public override bool Equals(object? obj
) =>
34 obj
is TransitionTime
&& Equals((TransitionTime
)obj
);
36 public static bool operator ==(TransitionTime t1
, TransitionTime t2
) => t1
.Equals(t2
);
38 public static bool operator !=(TransitionTime t1
, TransitionTime t2
) => !t1
.Equals(t2
);
40 public bool Equals(TransitionTime other
) =>
41 _isFixedDateRule
== other
._isFixedDateRule
&&
42 _timeOfDay
== other
._timeOfDay
&&
43 _month
== other
._month
&&
44 (other
._isFixedDateRule
?
46 _week
== other
._week
&& _dayOfWeek
== other
._dayOfWeek
);
48 public override int GetHashCode() => (int)_month ^
(int)_week
<< 8;
50 private TransitionTime(DateTime timeOfDay
, int month
, int week
, int day
, DayOfWeek dayOfWeek
, bool isFixedDateRule
)
52 ValidateTransitionTime(timeOfDay
, month
, week
, day
, dayOfWeek
);
54 _timeOfDay
= timeOfDay
;
58 _dayOfWeek
= dayOfWeek
;
59 _isFixedDateRule
= isFixedDateRule
;
62 public static TransitionTime
CreateFixedDateRule(DateTime timeOfDay
, int month
, int day
) =>
63 new TransitionTime(timeOfDay
, month
, 1, day
, DayOfWeek
.Sunday
, isFixedDateRule
: true);
65 public static TransitionTime
CreateFloatingDateRule(DateTime timeOfDay
, int month
, int week
, DayOfWeek dayOfWeek
) =>
66 new TransitionTime(timeOfDay
, month
, week
, 1, dayOfWeek
, isFixedDateRule
: false);
69 /// Helper function that validates a TransitionTime instance.
71 private static void ValidateTransitionTime(DateTime timeOfDay
, int month
, int week
, int day
, DayOfWeek dayOfWeek
)
73 if (timeOfDay
.Kind
!= DateTimeKind
.Unspecified
)
75 throw new ArgumentException(SR
.Argument_DateTimeKindMustBeUnspecified
, nameof(timeOfDay
));
79 if (month
< 1 || month
> 12)
81 throw new ArgumentOutOfRangeException(nameof(month
), SR
.ArgumentOutOfRange_MonthParam
);
85 if (day
< 1 || day
> 31)
87 throw new ArgumentOutOfRangeException(nameof(day
), SR
.ArgumentOutOfRange_DayParam
);
91 if (week
< 1 || week
> 5)
93 throw new ArgumentOutOfRangeException(nameof(week
), SR
.ArgumentOutOfRange_Week
);
96 // DayOfWeek range 0-6
97 if ((int)dayOfWeek
< 0 || (int)dayOfWeek
> 6)
99 throw new ArgumentOutOfRangeException(nameof(dayOfWeek
), SR
.ArgumentOutOfRange_DayOfWeek
);
102 timeOfDay
.GetDatePart(out int timeOfDayYear
, out int timeOfDayMonth
, out int timeOfDayDay
);
103 if (timeOfDayYear
!= 1 || timeOfDayMonth
!= 1 || timeOfDayDay
!= 1 || (timeOfDay
.Ticks
% TimeSpan
.TicksPerMillisecond
!= 0))
105 throw new ArgumentException(SR
.Argument_DateTimeHasTicks
, nameof(timeOfDay
));
109 void IDeserializationCallback
.OnDeserialization(object? sender
)
111 // OnDeserialization is called after each instance of this class is deserialized.
112 // This callback method performs TransitionTime validation after being deserialized.
114 // On Unix, TimeZoneInfos are created with empty/default TransitionTimes, since
115 // TransitionTimes are not used on Unix. When deserializing TransitionTimes, only
116 // validate it if it isn't an empty/default instance.
121 ValidateTransitionTime(_timeOfDay
, _month
, _week
, _day
, _dayOfWeek
);
123 catch (ArgumentException e
)
125 throw new SerializationException(SR
.Serialization_InvalidData
, e
);
130 void ISerializable
.GetObjectData(SerializationInfo info
, StreamingContext context
)
134 throw new ArgumentNullException(nameof(info
));
137 info
.AddValue("TimeOfDay", _timeOfDay
); // Do not rename (binary serialization)
138 info
.AddValue("Month", _month
); // Do not rename (binary serialization)
139 info
.AddValue("Week", _week
); // Do not rename (binary serialization)
140 info
.AddValue("Day", _day
); // Do not rename (binary serialization)
141 info
.AddValue("DayOfWeek", _dayOfWeek
); // Do not rename (binary serialization)
142 info
.AddValue("IsFixedDateRule", _isFixedDateRule
); // Do not rename (binary serialization)
145 private TransitionTime(SerializationInfo info
, StreamingContext context
)
149 throw new ArgumentNullException(nameof(info
));
152 _timeOfDay
= (DateTime
)info
.GetValue("TimeOfDay", typeof(DateTime
))!; // Do not rename (binary serialization)
153 _month
= (byte)info
.GetValue("Month", typeof(byte))!; // Do not rename (binary serialization)
154 _week
= (byte)info
.GetValue("Week", typeof(byte))!; // Do not rename (binary serialization)
155 _day
= (byte)info
.GetValue("Day", typeof(byte))!; // Do not rename (binary serialization)
156 _dayOfWeek
= (DayOfWeek
)info
.GetValue("DayOfWeek", typeof(DayOfWeek
))!; // Do not rename (binary serialization)
157 _isFixedDateRule
= (bool)info
.GetValue("IsFixedDateRule", typeof(bool))!; // Do not rename (binary serialization)