TimeZoneInfo.TransitionTime.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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.
  4. using System.Runtime.Serialization;
  5. namespace System
  6. {
  7. public sealed partial class TimeZoneInfo
  8. {
  9. [Serializable]
  10. public readonly struct TransitionTime : IEquatable<TransitionTime>, ISerializable, IDeserializationCallback
  11. {
  12. private readonly DateTime _timeOfDay;
  13. private readonly byte _month;
  14. private readonly byte _week;
  15. private readonly byte _day;
  16. private readonly DayOfWeek _dayOfWeek;
  17. private readonly bool _isFixedDateRule;
  18. public DateTime TimeOfDay => _timeOfDay;
  19. public int Month => _month;
  20. public int Week => _week;
  21. public int Day => _day;
  22. public DayOfWeek DayOfWeek => _dayOfWeek;
  23. public bool IsFixedDateRule => _isFixedDateRule;
  24. public override bool Equals(object obj) =>
  25. obj is TransitionTime && Equals((TransitionTime)obj);
  26. public static bool operator ==(TransitionTime t1, TransitionTime t2) => t1.Equals(t2);
  27. public static bool operator !=(TransitionTime t1, TransitionTime t2) => !t1.Equals(t2);
  28. public bool Equals(TransitionTime other) =>
  29. _isFixedDateRule == other._isFixedDateRule &&
  30. _timeOfDay == other._timeOfDay &&
  31. _month == other._month &&
  32. (other._isFixedDateRule ?
  33. _day == other._day :
  34. _week == other._week && _dayOfWeek == other._dayOfWeek);
  35. public override int GetHashCode() => (int)_month ^ (int)_week << 8;
  36. private TransitionTime(DateTime timeOfDay, int month, int week, int day, DayOfWeek dayOfWeek, bool isFixedDateRule)
  37. {
  38. ValidateTransitionTime(timeOfDay, month, week, day, dayOfWeek);
  39. _timeOfDay = timeOfDay;
  40. _month = (byte)month;
  41. _week = (byte)week;
  42. _day = (byte)day;
  43. _dayOfWeek = dayOfWeek;
  44. _isFixedDateRule = isFixedDateRule;
  45. }
  46. public static TransitionTime CreateFixedDateRule(DateTime timeOfDay, int month, int day) =>
  47. new TransitionTime(timeOfDay, month, 1, day, DayOfWeek.Sunday, isFixedDateRule: true);
  48. public static TransitionTime CreateFloatingDateRule(DateTime timeOfDay, int month, int week, DayOfWeek dayOfWeek) =>
  49. new TransitionTime(timeOfDay, month, week, 1, dayOfWeek, isFixedDateRule: false);
  50. /// <summary>
  51. /// Helper function that validates a TransitionTime instance.
  52. /// </summary>
  53. private static void ValidateTransitionTime(DateTime timeOfDay, int month, int week, int day, DayOfWeek dayOfWeek)
  54. {
  55. if (timeOfDay.Kind != DateTimeKind.Unspecified)
  56. {
  57. throw new ArgumentException(SR.Argument_DateTimeKindMustBeUnspecified, nameof(timeOfDay));
  58. }
  59. // Month range 1-12
  60. if (month < 1 || month > 12)
  61. {
  62. throw new ArgumentOutOfRangeException(nameof(month), SR.ArgumentOutOfRange_MonthParam);
  63. }
  64. // Day range 1-31
  65. if (day < 1 || day > 31)
  66. {
  67. throw new ArgumentOutOfRangeException(nameof(day), SR.ArgumentOutOfRange_DayParam);
  68. }
  69. // Week range 1-5
  70. if (week < 1 || week > 5)
  71. {
  72. throw new ArgumentOutOfRangeException(nameof(week), SR.ArgumentOutOfRange_Week);
  73. }
  74. // DayOfWeek range 0-6
  75. if ((int)dayOfWeek < 0 || (int)dayOfWeek > 6)
  76. {
  77. throw new ArgumentOutOfRangeException(nameof(dayOfWeek), SR.ArgumentOutOfRange_DayOfWeek);
  78. }
  79. timeOfDay.GetDatePart(out int timeOfDayYear, out int timeOfDayMonth, out int timeOfDayDay);
  80. if (timeOfDayYear != 1 || timeOfDayMonth != 1 || timeOfDayDay != 1 || (timeOfDay.Ticks % TimeSpan.TicksPerMillisecond != 0))
  81. {
  82. throw new ArgumentException(SR.Argument_DateTimeHasTicks, nameof(timeOfDay));
  83. }
  84. }
  85. void IDeserializationCallback.OnDeserialization(object sender)
  86. {
  87. // OnDeserialization is called after each instance of this class is deserialized.
  88. // This callback method performs TransitionTime validation after being deserialized.
  89. try
  90. {
  91. ValidateTransitionTime(_timeOfDay, _month, _week, _day, _dayOfWeek);
  92. }
  93. catch (ArgumentException e)
  94. {
  95. throw new SerializationException(SR.Serialization_InvalidData, e);
  96. }
  97. }
  98. void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
  99. {
  100. if (info == null)
  101. {
  102. throw new ArgumentNullException(nameof(info));
  103. }
  104. info.AddValue("TimeOfDay", _timeOfDay); // Do not rename (binary serialization)
  105. info.AddValue("Month", _month); // Do not rename (binary serialization)
  106. info.AddValue("Week", _week); // Do not rename (binary serialization)
  107. info.AddValue("Day", _day); // Do not rename (binary serialization)
  108. info.AddValue("DayOfWeek", _dayOfWeek); // Do not rename (binary serialization)
  109. info.AddValue("IsFixedDateRule", _isFixedDateRule); // Do not rename (binary serialization)
  110. }
  111. private TransitionTime(SerializationInfo info, StreamingContext context)
  112. {
  113. if (info == null)
  114. {
  115. throw new ArgumentNullException(nameof(info));
  116. }
  117. _timeOfDay = (DateTime)info.GetValue("TimeOfDay", typeof(DateTime)); // Do not rename (binary serialization)
  118. _month = (byte)info.GetValue("Month", typeof(byte)); // Do not rename (binary serialization)
  119. _week = (byte)info.GetValue("Week", typeof(byte)); // Do not rename (binary serialization)
  120. _day = (byte)info.GetValue("Day", typeof(byte)); // Do not rename (binary serialization)
  121. _dayOfWeek = (DayOfWeek)info.GetValue("DayOfWeek", typeof(DayOfWeek)); // Do not rename (binary serialization)
  122. _isFixedDateRule = (bool)info.GetValue("IsFixedDateRule", typeof(bool)); // Do not rename (binary serialization)
  123. }
  124. }
  125. }
  126. }