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 5 using System.Collections.Generic; 6 using System.Globalization; 7 using System.Threading; 8 using Xunit; 9 10 namespace System.Tests 11 { 12 public static partial class DateTimeOffsetTests 13 { 14 [Fact] MaxValue()15 public static void MaxValue() 16 { 17 VerifyDateTimeOffset(DateTimeOffset.MaxValue, 9999, 12, 31, 23, 59, 59, 999, TimeSpan.Zero); 18 } 19 20 [Fact] MinValue()21 public static void MinValue() 22 { 23 VerifyDateTimeOffset(DateTimeOffset.MinValue, 1, 1, 1, 0, 0, 0, 0, TimeSpan.Zero); 24 } 25 26 [Fact] Ctor_Empty()27 public static void Ctor_Empty() 28 { 29 VerifyDateTimeOffset(new DateTimeOffset(), 1, 1, 1, 0, 0, 0, 0, TimeSpan.Zero); 30 VerifyDateTimeOffset(default(DateTimeOffset), 1, 1, 1, 0, 0, 0, 0, TimeSpan.Zero); 31 } 32 33 [Fact] Ctor_DateTime()34 public static void Ctor_DateTime() 35 { 36 var dateTimeOffset = new DateTimeOffset(new DateTime(2012, 6, 11, 0, 0, 0, 0, DateTimeKind.Utc)); 37 VerifyDateTimeOffset(dateTimeOffset, 2012, 6, 11, 0, 0, 0, 0, TimeSpan.Zero); 38 39 dateTimeOffset = new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 4, DateTimeKind.Local)); 40 VerifyDateTimeOffset(dateTimeOffset, 1986, 8, 15, 10, 20, 5, 4, null); 41 42 DateTimeOffset today = new DateTimeOffset(DateTime.Today); 43 DateTimeOffset now = DateTimeOffset.Now.Date; 44 VerifyDateTimeOffset(today, now.Year, now.Month, now.Day, 0, 0, 0, 0, now.Offset); 45 46 today = new DateTimeOffset(new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, DateTimeKind.Utc)); 47 Assert.Equal(TimeSpan.Zero, today.Offset); 48 Assert.False(today.UtcDateTime.IsDaylightSavingTime()); 49 } 50 51 [Fact] Ctor_DateTime_Invalid()52 public static void Ctor_DateTime_Invalid() 53 { 54 // DateTime < DateTimeOffset.MinValue 55 DateTimeOffset min = DateTimeOffset.MinValue; 56 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year - 1, min.Day, min.Hour, min.Minute, min.Second, min.Millisecond, DateTimeKind.Utc))); 57 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year, min.Month - 1, min.Day, min.Hour, min.Minute, min.Second, min.Millisecond, DateTimeKind.Utc))); 58 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year, min.Month, min.Day - 1, min.Hour, min.Minute, min.Second, min.Millisecond, DateTimeKind.Utc))); 59 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year, min.Month, min.Day, min.Hour - 1, min.Minute, min.Second, min.Millisecond, DateTimeKind.Utc))); 60 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year, min.Month, min.Day, min.Hour, min.Minute - 1, min.Second, min.Millisecond, DateTimeKind.Utc))); 61 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year, min.Month, min.Day, min.Hour, min.Minute, min.Second - 1, min.Millisecond, DateTimeKind.Utc))); 62 AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecond", () => new DateTimeOffset(new DateTime(min.Year, min.Month, min.Day, min.Hour, min.Minute, min.Second, min.Millisecond - 1, DateTimeKind.Utc))); 63 64 // DateTime > DateTimeOffset.MaxValue 65 DateTimeOffset max = DateTimeOffset.MaxValue; 66 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year + 1, max.Month, max.Day, max.Hour, max.Minute, max.Second, max.Millisecond, DateTimeKind.Utc))); 67 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year, max.Month + 1, max.Day, max.Hour, max.Minute, max.Second, max.Millisecond, DateTimeKind.Utc))); 68 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year, max.Month, max.Day + 1, max.Hour, max.Minute, max.Second, max.Millisecond, DateTimeKind.Utc))); 69 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year, max.Month, max.Day, max.Hour + 1, max.Minute, max.Second, max.Millisecond, DateTimeKind.Utc))); 70 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year, max.Month, max.Day, max.Hour, max.Minute + 1, max.Second, max.Millisecond, DateTimeKind.Utc))); 71 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year, max.Month, max.Day, max.Hour, max.Minute, max.Second + 1, max.Millisecond, DateTimeKind.Utc))); 72 AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecond", () => new DateTimeOffset(new DateTime(max.Year, max.Month, max.Day, max.Hour, max.Minute, max.Second, max.Millisecond + 1, DateTimeKind.Utc))); 73 } 74 75 [Fact] Ctor_DateTime_TimeSpan()76 public static void Ctor_DateTime_TimeSpan() 77 { 78 var dateTimeOffset = new DateTimeOffset(DateTime.MinValue, TimeSpan.FromHours(-14)); 79 VerifyDateTimeOffset(dateTimeOffset, 1, 1, 1, 0, 0, 0, 0, TimeSpan.FromHours(-14)); 80 81 dateTimeOffset = new DateTimeOffset(DateTime.MaxValue, TimeSpan.FromHours(14)); 82 VerifyDateTimeOffset(dateTimeOffset, 9999, 12, 31, 23, 59, 59, 999, TimeSpan.FromHours(14)); 83 84 dateTimeOffset = new DateTimeOffset(new DateTime(2012, 12, 31, 13, 50, 10), TimeSpan.Zero); 85 VerifyDateTimeOffset(dateTimeOffset, 2012, 12, 31, 13, 50, 10, 0, TimeSpan.Zero); 86 } 87 88 [Fact] Ctor_DateTime_TimeSpan_Invalid()89 public static void Ctor_DateTime_TimeSpan_Invalid() 90 { 91 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(DateTime.Now, TimeSpan.FromHours(15))); // Local time and non timezone timespan 92 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(DateTime.Now, TimeSpan.FromHours(-15))); // Local time and non timezone timespan 93 94 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(DateTime.UtcNow, TimeSpan.FromHours(1))); // Local time and non zero timespan 95 96 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(DateTime.UtcNow, new TimeSpan(0, 0, 3))); // TimeSpan is not whole minutes 97 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(DateTime.UtcNow, new TimeSpan(0, 0, -3))); // TimeSpan is not whole minutes 98 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(DateTime.UtcNow, new TimeSpan(0, 0, 0, 0, 3))); // TimeSpan is not whole minutes 99 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(DateTime.UtcNow, new TimeSpan(0, 0, 0, 0, -3))); // TimeSpan is not whole minutes 100 101 // DateTime < DateTimeOffset.MinValue 102 DateTimeOffset min = DateTimeOffset.MinValue; 103 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year - 1, min.Day, min.Hour, min.Minute, min.Second, min.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 104 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year, min.Month - 1, min.Day, min.Hour, min.Minute, min.Second, min.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 105 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year, min.Month, min.Day - 1, min.Hour, min.Minute, min.Second, min.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 106 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year, min.Month, min.Day, min.Hour - 1, min.Minute, min.Second, min.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 107 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year, min.Month, min.Day, min.Hour, min.Minute - 1, min.Second, min.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 108 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(min.Year, min.Month, min.Day, min.Hour, min.Minute, min.Second - 1, min.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 109 AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecond", () => new DateTimeOffset(new DateTime(min.Year, min.Month, min.Day, min.Hour, min.Minute, min.Second, min.Millisecond - 1, DateTimeKind.Utc), TimeSpan.Zero)); 110 111 // DateTime > DateTimeOffset.MaxValue 112 DateTimeOffset max = DateTimeOffset.MaxValue; 113 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year + 1, max.Month, max.Day, max.Hour, max.Minute, max.Second, max.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 114 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year, max.Month + 1, max.Day, max.Hour, max.Minute, max.Second, max.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 115 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year, max.Month, max.Day + 1, max.Hour, max.Minute, max.Second, max.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 116 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year, max.Month, max.Day, max.Hour + 1, max.Minute, max.Second, max.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 117 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year, max.Month, max.Day, max.Hour, max.Minute + 1, max.Second, max.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 118 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(new DateTime(max.Year, max.Month, max.Day, max.Hour, max.Minute, max.Second + 1, max.Millisecond, DateTimeKind.Utc), TimeSpan.Zero)); 119 AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecond", () => new DateTimeOffset(new DateTime(max.Year, max.Month, max.Day, max.Hour, max.Minute, max.Second, max.Millisecond + 1, DateTimeKind.Utc), TimeSpan.Zero)); 120 121 // Invalid offset 122 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(DateTime.Now, TimeSpan.FromTicks(1))); 123 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(DateTime.UtcNow, TimeSpan.FromTicks(1))); 124 } 125 126 [Fact] Ctor_Long_TimeSpan()127 public static void Ctor_Long_TimeSpan() 128 { 129 var expected = new DateTime(1, 2, 3, 4, 5, 6, 7); 130 var dateTimeOffset = new DateTimeOffset(expected.Ticks, TimeSpan.Zero); 131 VerifyDateTimeOffset(dateTimeOffset, dateTimeOffset.Year, dateTimeOffset.Month, dateTimeOffset.Day, dateTimeOffset.Hour, dateTimeOffset.Minute, dateTimeOffset.Second, dateTimeOffset.Millisecond, TimeSpan.Zero); 132 } 133 134 [Fact] Ctor_Long_TimeSpan_Invalid()135 public static void Ctor_Long_TimeSpan_Invalid() 136 { 137 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(0, new TimeSpan(0, 0, 3))); // TimeSpan is not whole minutes 138 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(0, new TimeSpan(0, 0, -3))); // TimeSpan is not whole minutes 139 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(0, new TimeSpan(0, 0, 0, 0, 3))); // TimeSpan is not whole minutes 140 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(0, new TimeSpan(0, 0, 0, 0, -3))); // TimeSpan is not whole minutes 141 142 AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => new DateTimeOffset(0, TimeSpan.FromHours(-15))); // TimeZone.Offset > 14 143 AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => new DateTimeOffset(0, TimeSpan.FromHours(15))); // TimeZone.Offset < -14 144 145 AssertExtensions.Throws<ArgumentOutOfRangeException>("ticks", () => new DateTimeOffset(DateTimeOffset.MinValue.Ticks - 1, TimeSpan.Zero)); // Ticks < DateTimeOffset.MinValue.Ticks 146 AssertExtensions.Throws<ArgumentOutOfRangeException>("ticks", () => new DateTimeOffset(DateTimeOffset.MaxValue.Ticks + 1, TimeSpan.Zero)); // Ticks > DateTimeOffset.MaxValue.Ticks 147 } 148 149 [Fact] Ctor_Int_Int_Int_Int_Int_Int_Int_TimeSpan()150 public static void Ctor_Int_Int_Int_Int_Int_Int_Int_TimeSpan() 151 { 152 var dateTimeOffset = new DateTimeOffset(1973, 10, 6, 14, 30, 0, 500, TimeSpan.Zero); 153 VerifyDateTimeOffset(dateTimeOffset, 1973, 10, 6, 14, 30, 0, 500, TimeSpan.Zero); 154 } 155 156 [Fact] Ctor_Int_Int_Int_Int_Int_Int_Int_TimeSpan_Invalid()157 public static void Ctor_Int_Int_Int_Int_Int_Int_Int_TimeSpan_Invalid() 158 { 159 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, 1, new TimeSpan(0, 0, 3))); // TimeSpan is not whole minutes 160 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, 1, new TimeSpan(0, 0, -3))); // TimeSpan is not whole minutes 161 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, 1, new TimeSpan(0, 0, 0, 0, 3))); // TimeSpan is not whole minutes 162 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, 1, new TimeSpan(0, 0, 0, 0, -3))); // TimeSpan is not whole minutes 163 164 AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, 1, TimeSpan.FromHours(-15))); // TimeZone.Offset > 14 165 AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, 1, TimeSpan.FromHours(15))); // TimeZone.Offset < -14 166 167 // Invalid DateTime 168 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(0, 1, 1, 1, 1, 1, 1, TimeSpan.Zero)); // Year < 1 169 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(10000, 1, 1, 1, 1, 1, 1, TimeSpan.Zero)); // Year > 9999 170 171 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 0, 1, 1, 1, 1, 1, TimeSpan.Zero)); // Month < 1 172 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 13, 1, 1, 1, 1, 1, TimeSpan.Zero)); // Motnh > 23 173 174 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 0, 1, 1, 1, 1, TimeSpan.Zero)); // Day < 1 175 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 32, 1, 1, 1, 1, TimeSpan.Zero)); // Day > days in month 176 177 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, -1, 1, 1, 1, TimeSpan.Zero)); // Hour < 0 178 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, 24, 1, 1, 1, TimeSpan.Zero)); // Hour > 23 179 180 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, 1, -1, 1, 1, TimeSpan.Zero)); // Minute < 0 181 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, 1, 60, 1, 1, TimeSpan.Zero)); // Minute > 59 182 183 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, 1, 1, -1, 1, TimeSpan.Zero)); // Second < 0 184 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, 1, 1, 60, 1, TimeSpan.Zero)); // Second > 59 185 186 AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecond", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, -1, TimeSpan.Zero)); // Millisecond < 0 187 AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecond", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, 1000, TimeSpan.Zero)); // Millisecond > 999 188 189 // DateTime < DateTimeOffset.MinValue 190 DateTimeOffset min = DateTimeOffset.MinValue; 191 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year - 1, min.Month, min.Day, min.Hour, min.Minute, min.Second, min.Millisecond, TimeSpan.Zero)); 192 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year, min.Month - 1, min.Day, min.Hour, min.Minute, min.Second, min.Millisecond, TimeSpan.Zero)); 193 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year, min.Month, min.Day - 1, min.Hour, min.Minute, min.Second, min.Millisecond, TimeSpan.Zero)); 194 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year, min.Month, min.Day, min.Hour - 1, min.Minute, min.Second, min.Millisecond, TimeSpan.Zero)); 195 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year, min.Month, min.Day, min.Hour, min.Minute - 1, min.Second, min.Millisecond, TimeSpan.Zero)); 196 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year, min.Month, min.Day, min.Hour, min.Minute, min.Second - 1, min.Millisecond, TimeSpan.Zero)); 197 AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecond", () => new DateTimeOffset(min.Year, min.Month, min.Day, min.Hour, min.Minute, min.Second, min.Millisecond - 1, TimeSpan.Zero)); 198 199 // DateTime > DateTimeOffset.MaxValue 200 DateTimeOffset max = DateTimeOffset.MaxValue; 201 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year + 1, max.Month, max.Day, max.Hour, max.Minute, max.Second, max.Millisecond, TimeSpan.Zero)); 202 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year, max.Month + 1, max.Day + 1, max.Hour, max.Minute, max.Second, max.Millisecond, TimeSpan.Zero)); 203 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year, max.Month, max.Day + 1, max.Hour, max.Minute, max.Second, max.Millisecond, TimeSpan.Zero)); 204 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year, max.Month, max.Day, max.Hour + 1, max.Minute, max.Second, max.Millisecond, TimeSpan.Zero)); 205 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year, max.Month, max.Day, max.Hour, max.Minute + 1, max.Second, max.Millisecond, TimeSpan.Zero)); 206 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year, max.Month, max.Day, max.Hour, max.Minute, max.Second + 1, max.Millisecond, TimeSpan.Zero)); 207 AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecond", () => new DateTimeOffset(max.Year, max.Month, max.Day, max.Hour, max.Minute, max.Second, max.Millisecond + 1, TimeSpan.Zero)); 208 } 209 210 [Fact] Ctor_Int_Int_Int_Int_Int_Int_TimeSpan()211 public static void Ctor_Int_Int_Int_Int_Int_Int_TimeSpan() 212 { 213 var dateTimeOffset = new DateTimeOffset(1973, 10, 6, 14, 30, 0, TimeSpan.Zero); 214 VerifyDateTimeOffset(dateTimeOffset, 1973, 10, 6, 14, 30, 0, 0, TimeSpan.Zero); 215 } 216 217 [Fact] Ctor_Int_Int_Int_Int_Int_Int_TimeSpan_Invalid()218 public static void Ctor_Int_Int_Int_Int_Int_Int_TimeSpan_Invalid() 219 { 220 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, new TimeSpan(0, 0, 3))); // TimeSpan is not whole minutes 221 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, new TimeSpan(0, 0, -3))); // TimeSpan is not whole minutes 222 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, new TimeSpan(0, 0, 0, 0, 3))); // TimeSpan is not whole minutes 223 AssertExtensions.Throws<ArgumentException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, new TimeSpan(0, 0, 0, 0, -3))); // TimeSpan is not whole minutes 224 225 AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, TimeSpan.FromHours(-15))); // TimeZone.Offset > 14 226 AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => new DateTimeOffset(1, 1, 1, 1, 1, 1, TimeSpan.FromHours(15))); // TimeZone.Offset < -14 227 228 // Invalid DateTime 229 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(0, 1, 1, 1, 1, 1, TimeSpan.Zero)); // Year < 1 230 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(10000, 1, 1, 1, 1, 1, TimeSpan.Zero)); // Year > 9999 231 232 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 0, 1, 1, 1, 1, TimeSpan.Zero)); // Month < 1 233 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 13, 1, 1, 1, 1, TimeSpan.Zero)); // Month > 23 234 235 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 0, 1, 1, 1, TimeSpan.Zero)); // Day < 1 236 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 32, 1, 1, 1, TimeSpan.Zero)); // Day > days in month 237 238 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, -1, 1, 1, TimeSpan.Zero)); // Hour < 0 239 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, 24, 1, 1, TimeSpan.Zero)); // Hour > 23 240 241 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, 1, -1, 1, TimeSpan.Zero)); // Minute < 0 242 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, 1, 60, 1, TimeSpan.Zero)); // Minute > 59 243 244 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, 1, 1, -1, TimeSpan.Zero)); // Second < 0 245 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(1, 1, 1, 1, 1, 60, TimeSpan.Zero)); // Second > 59 246 247 // DateTime < DateTimeOffset.MinValue 248 DateTimeOffset min = DateTimeOffset.MinValue; 249 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year - 1, min.Month, min.Day, min.Hour, min.Minute, min.Second, TimeSpan.Zero)); 250 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year, min.Month - 1, min.Day, min.Hour, min.Minute, min.Second, TimeSpan.Zero)); 251 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year, min.Month, min.Day - 1, min.Hour, min.Minute, min.Second, TimeSpan.Zero)); 252 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year, min.Month, min.Day, min.Hour - 1, min.Minute, min.Second, TimeSpan.Zero)); 253 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year, min.Month, min.Day, min.Hour, min.Minute - 1, min.Second, TimeSpan.Zero)); 254 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(min.Year, min.Month, min.Day, min.Hour, min.Minute, min.Second - 1, TimeSpan.Zero)); 255 256 // DateTime > DateTimeOffset.MaxValue 257 DateTimeOffset max = DateTimeOffset.MaxValue; 258 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year + 1, max.Month, max.Day, max.Hour, max.Minute, max.Second, TimeSpan.Zero)); 259 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year, max.Month + 1, max.Day + 1, max.Hour, max.Minute, max.Second, TimeSpan.Zero)); 260 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year, max.Month, max.Day + 1, max.Hour, max.Minute, max.Second, TimeSpan.Zero)); 261 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year, max.Month, max.Day, max.Hour + 1, max.Minute, max.Second, TimeSpan.Zero)); 262 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year, max.Month, max.Day, max.Hour, max.Minute + 1, max.Second, TimeSpan.Zero)); 263 AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => new DateTimeOffset(max.Year, max.Month, max.Day, max.Hour, max.Minute, max.Second + 1, TimeSpan.Zero)); 264 } 265 266 [Fact] ImplicitCast_DateTime()267 public static void ImplicitCast_DateTime() 268 { 269 DateTime dateTime = new DateTime(2012, 6, 11, 0, 0, 0, 0, DateTimeKind.Utc); 270 DateTimeOffset dateTimeOffset = dateTime; 271 VerifyDateTimeOffset(dateTimeOffset, 2012, 6, 11, 0, 0, 0, 0, TimeSpan.Zero); 272 } 273 274 [Fact] AddSubtract_TimeSpan()275 public static void AddSubtract_TimeSpan() 276 { 277 var dateTimeOffset = new DateTimeOffset(new DateTime(2012, 6, 18, 10, 5, 1, 0, DateTimeKind.Utc)); 278 TimeSpan timeSpan = dateTimeOffset.TimeOfDay; 279 280 DateTimeOffset newDate = dateTimeOffset.Subtract(timeSpan); 281 Assert.Equal(new DateTimeOffset(new DateTime(2012, 6, 18, 0, 0, 0, 0, DateTimeKind.Utc)).Ticks, newDate.Ticks); 282 Assert.Equal(dateTimeOffset.Ticks, newDate.Add(timeSpan).Ticks); 283 } 284 Subtract_TimeSpan_TestData()285 public static IEnumerable<object[]> Subtract_TimeSpan_TestData() 286 { 287 var dateTimeOffset = new DateTimeOffset(new DateTime(2012, 6, 18, 10, 5, 1, 0, DateTimeKind.Utc)); 288 289 yield return new object[] { dateTimeOffset, new TimeSpan(10, 5, 1), new DateTimeOffset(new DateTime(2012, 6, 18, 0, 0, 0, 0, DateTimeKind.Utc)) }; 290 yield return new object[] { dateTimeOffset, new TimeSpan(-10, -5, -1), new DateTimeOffset(new DateTime(2012, 6, 18, 20, 10, 2, 0, DateTimeKind.Utc)) }; 291 } 292 293 [Theory] 294 [MemberData(nameof(Subtract_TimeSpan_TestData))] Subtract_TimeSpan(DateTimeOffset dt, TimeSpan ts, DateTimeOffset expected)295 public static void Subtract_TimeSpan(DateTimeOffset dt, TimeSpan ts, DateTimeOffset expected) 296 { 297 Assert.Equal(expected, dt - ts); 298 Assert.Equal(expected, dt.Subtract(ts)); 299 } 300 Subtract_DateTimeOffset_TestData()301 public static IEnumerable<object[]> Subtract_DateTimeOffset_TestData() 302 { 303 var dateTimeOffset1 = new DateTimeOffset(new DateTime(1996, 6, 3, 22, 15, 0, DateTimeKind.Utc)); 304 var dateTimeOffset2 = new DateTimeOffset(new DateTime(1996, 12, 6, 13, 2, 0, DateTimeKind.Utc)); 305 var dateTimeOffset3 = new DateTimeOffset(new DateTime(1996, 10, 12, 8, 42, 0, DateTimeKind.Utc)); 306 307 yield return new object[] { dateTimeOffset2, dateTimeOffset1, new TimeSpan(185, 14, 47, 0) }; 308 yield return new object[] { dateTimeOffset1, dateTimeOffset2, new TimeSpan(-185, -14, -47, 0) }; 309 yield return new object[] { dateTimeOffset1, dateTimeOffset2, new TimeSpan(-185, -14, -47, 0) }; 310 } 311 312 [Theory] 313 [MemberData(nameof(Subtract_DateTimeOffset_TestData))] Subtract_DateTimeOffset(DateTimeOffset dt1, DateTimeOffset dt2, TimeSpan expected)314 public static void Subtract_DateTimeOffset(DateTimeOffset dt1, DateTimeOffset dt2, TimeSpan expected) 315 { 316 Assert.Equal(expected, dt1 - dt2); 317 Assert.Equal(expected, dt1.Subtract(dt2)); 318 } 319 Add_TimeSpan_TestData()320 public static IEnumerable<object[]> Add_TimeSpan_TestData() 321 { 322 yield return new object[] { new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)), new TimeSpan(10), new DateTimeOffset(new DateTime(1010, DateTimeKind.Utc)) }; 323 yield return new object[] { new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)), TimeSpan.Zero, new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)) }; 324 yield return new object[] { new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)), new TimeSpan(-10), new DateTimeOffset(new DateTime(990, DateTimeKind.Utc)) }; 325 } 326 327 [Theory] 328 [MemberData(nameof(Add_TimeSpan_TestData))] Add_TimeSpan(DateTimeOffset dateTimeOffset, TimeSpan timeSpan, DateTimeOffset expected)329 public static void Add_TimeSpan(DateTimeOffset dateTimeOffset, TimeSpan timeSpan, DateTimeOffset expected) 330 { 331 Assert.Equal(expected, dateTimeOffset.Add(timeSpan)); 332 Assert.Equal(expected, dateTimeOffset + timeSpan); 333 } 334 335 [Fact] Add_TimeSpan_NewDateOutOfRange_ThrowsArgumentOutOfRangeException()336 public static void Add_TimeSpan_NewDateOutOfRange_ThrowsArgumentOutOfRangeException() 337 { 338 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MinValue.Add(TimeSpan.FromTicks(-1))); 339 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MaxValue.Add(TimeSpan.FromTicks(11))); 340 } 341 AddYears_TestData()342 public static IEnumerable<object[]> AddYears_TestData() 343 { 344 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 10, new DateTimeOffset(new DateTime(1996, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)) }; 345 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 0, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)) }; 346 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), -10, new DateTimeOffset(new DateTime(1976, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)) }; 347 } 348 349 [Theory] 350 [MemberData(nameof(AddYears_TestData))] AddYears(DateTimeOffset dateTimeOffset, int years, DateTimeOffset expected)351 public static void AddYears(DateTimeOffset dateTimeOffset, int years, DateTimeOffset expected) 352 { 353 Assert.Equal(expected, dateTimeOffset.AddYears(years)); 354 } 355 356 [Fact] AddYears_NewDateOutOfRange_ThrowsArgumentOutOfRangeException()357 public static void AddYears_NewDateOutOfRange_ThrowsArgumentOutOfRangeException() 358 { 359 AssertExtensions.Throws<ArgumentOutOfRangeException>("years", () => DateTimeOffset.Now.AddYears(10001)); 360 AssertExtensions.Throws<ArgumentOutOfRangeException>("years", () => DateTimeOffset.Now.AddYears(-10001)); 361 362 AssertExtensions.Throws<ArgumentOutOfRangeException>("months", () => DateTimeOffset.MaxValue.AddYears(1)); 363 AssertExtensions.Throws<ArgumentOutOfRangeException>("months", () => DateTimeOffset.MinValue.AddYears(-1)); 364 } 365 AddMonths_TestData()366 public static IEnumerable<object[]> AddMonths_TestData() 367 { 368 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 2, new DateTimeOffset(new DateTime(1986, 10, 15, 10, 20, 5, 70, DateTimeKind.Utc)) }; 369 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 0, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)) }; 370 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), -2, new DateTimeOffset(new DateTime(1986, 6, 15, 10, 20, 5, 70, DateTimeKind.Utc)) }; 371 } 372 373 [Theory] 374 [MemberData(nameof(AddMonths_TestData))] AddMonths(DateTimeOffset dateTimeOffset, int months, DateTimeOffset expected)375 public static void AddMonths(DateTimeOffset dateTimeOffset, int months, DateTimeOffset expected) 376 { 377 Assert.Equal(expected, dateTimeOffset.AddMonths(months)); 378 } 379 380 [Fact] AddMonths_NewDateOutOfRange_ThrowsArgumentOutOfRangeException()381 public static void AddMonths_NewDateOutOfRange_ThrowsArgumentOutOfRangeException() 382 { 383 AssertExtensions.Throws<ArgumentOutOfRangeException>("months", () => DateTimeOffset.Now.AddMonths(120001)); 384 AssertExtensions.Throws<ArgumentOutOfRangeException>("months", () => DateTimeOffset.Now.AddMonths(-120001)); 385 386 AssertExtensions.Throws<ArgumentOutOfRangeException>("months", () => DateTimeOffset.MaxValue.AddMonths(1)); 387 AssertExtensions.Throws<ArgumentOutOfRangeException>("months", () => DateTimeOffset.MinValue.AddMonths(-1)); 388 } 389 AddDays_TestData()390 public static IEnumerable<object[]> AddDays_TestData() 391 { 392 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 2, new DateTimeOffset(new DateTime(1986, 8, 17, 10, 20, 5, 70, DateTimeKind.Utc)) }; 393 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 0, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)) }; 394 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), -2, new DateTimeOffset(new DateTime(1986, 8, 13, 10, 20, 5, 70, DateTimeKind.Utc)) }; 395 } 396 397 [Theory] 398 [MemberData(nameof(AddDays_TestData))] AddDays(DateTimeOffset dateTimeOffset, double days, DateTimeOffset expected)399 public static void AddDays(DateTimeOffset dateTimeOffset, double days, DateTimeOffset expected) 400 { 401 Assert.Equal(expected, dateTimeOffset.AddDays(days)); 402 } 403 404 [Fact] AddDays_NewDateOutOfRange_ThrowsArgumentOutOfRangeException()405 public static void AddDays_NewDateOutOfRange_ThrowsArgumentOutOfRangeException() 406 { 407 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MaxValue.AddDays(1)); 408 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MinValue.AddDays(-1)); 409 } 410 AddHours_TestData()411 public static IEnumerable<object[]> AddHours_TestData() 412 { 413 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 3, new DateTimeOffset(new DateTime(1986, 8, 15, 13, 20, 5, 70, DateTimeKind.Utc)) }; 414 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 0, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)) }; 415 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), -3, new DateTimeOffset(new DateTime(1986, 8, 15, 7, 20, 5, 70, DateTimeKind.Utc)) }; 416 } 417 418 [Theory] 419 [MemberData(nameof(AddHours_TestData))] AddHours(DateTimeOffset dateTimeOffset, double hours, DateTimeOffset expected)420 public static void AddHours(DateTimeOffset dateTimeOffset, double hours, DateTimeOffset expected) 421 { 422 Assert.Equal(expected, dateTimeOffset.AddHours(hours)); 423 } 424 425 [Fact] AddHours_NewDateOutOfRange_ThrowsArgumentOutOfRangeException()426 public static void AddHours_NewDateOutOfRange_ThrowsArgumentOutOfRangeException() 427 { 428 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MaxValue.AddHours(1)); 429 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MinValue.AddHours(-1)); 430 } 431 AddMinutes_TestData()432 public static IEnumerable<object[]> AddMinutes_TestData() 433 { 434 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 5, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 25, 5, 70, DateTimeKind.Utc)) }; 435 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 0, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)) }; 436 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), -5, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 15, 5, 70, DateTimeKind.Utc)) }; 437 } 438 439 [Theory] 440 [MemberData(nameof(AddMinutes_TestData))] AddMinutes(DateTimeOffset dateTimeOffset, double minutes, DateTimeOffset expected)441 public static void AddMinutes(DateTimeOffset dateTimeOffset, double minutes, DateTimeOffset expected) 442 { 443 Assert.Equal(expected, dateTimeOffset.AddMinutes(minutes)); 444 } 445 446 [Fact] AddMinutes_NewDateOutOfRange_ThrowsArgumentOutOfRangeException()447 public static void AddMinutes_NewDateOutOfRange_ThrowsArgumentOutOfRangeException() 448 { 449 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MaxValue.AddMinutes(1)); 450 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MinValue.AddMinutes(-1)); 451 } 452 AddSeconds_TestData()453 public static IEnumerable<object[]> AddSeconds_TestData() 454 { 455 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 30, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 35, 70, DateTimeKind.Utc)) }; 456 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 0, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)) }; 457 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), -3, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 2, 70, DateTimeKind.Utc)) }; 458 } 459 460 [Theory] 461 [MemberData(nameof(AddSeconds_TestData))] AddSeconds(DateTimeOffset dateTimeOffset, double seconds, DateTimeOffset expected)462 public static void AddSeconds(DateTimeOffset dateTimeOffset, double seconds, DateTimeOffset expected) 463 { 464 Assert.Equal(expected, dateTimeOffset.AddSeconds(seconds)); 465 } 466 467 [Fact] AddSeconds_NewDateOutOfRange_ThrowsArgumentOutOfRangeException()468 public static void AddSeconds_NewDateOutOfRange_ThrowsArgumentOutOfRangeException() 469 { 470 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MaxValue.AddSeconds(1)); 471 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MinValue.AddSeconds(-1)); 472 } 473 AddMilliseconds_TestData()474 public static IEnumerable<object[]> AddMilliseconds_TestData() 475 { 476 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 10, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 80, DateTimeKind.Utc)) }; 477 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), 0, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)) }; 478 yield return new object[] { new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 70, DateTimeKind.Utc)), -10, new DateTimeOffset(new DateTime(1986, 8, 15, 10, 20, 5, 60, DateTimeKind.Utc)) }; 479 } 480 481 [Theory] 482 [MemberData(nameof(AddMilliseconds_TestData))] AddMilliseconds(DateTimeOffset dateTimeOffset, double milliseconds, DateTimeOffset expected)483 public static void AddMilliseconds(DateTimeOffset dateTimeOffset, double milliseconds, DateTimeOffset expected) 484 { 485 Assert.Equal(expected, dateTimeOffset.AddMilliseconds(milliseconds)); 486 } 487 488 [Fact] AddMilliseconds_NewDateOutOfRange_ThrowsArgumentOutOfRangeException()489 public static void AddMilliseconds_NewDateOutOfRange_ThrowsArgumentOutOfRangeException() 490 { 491 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MaxValue.AddMilliseconds(1)); 492 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MinValue.AddMilliseconds(-1)); 493 } 494 AddTicks_TestData()495 public static IEnumerable<object[]> AddTicks_TestData() 496 { 497 yield return new object[] { new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)), 10, new DateTimeOffset(new DateTime(1010, DateTimeKind.Utc)) }; 498 yield return new object[] { new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)), 0, new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)) }; 499 yield return new object[] { new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)), -10, new DateTimeOffset(new DateTime(990, DateTimeKind.Utc)) }; 500 } 501 502 [Theory] 503 [MemberData(nameof(AddTicks_TestData))] AddTicks(DateTimeOffset dateTimeOffset, long ticks, DateTimeOffset expected)504 public static void AddTicks(DateTimeOffset dateTimeOffset, long ticks, DateTimeOffset expected) 505 { 506 Assert.Equal(expected, dateTimeOffset.AddTicks(ticks)); 507 } 508 509 [Fact] AddTicks_NewDateOutOfRange_ThrowsArgumentOutOfRangeException()510 public static void AddTicks_NewDateOutOfRange_ThrowsArgumentOutOfRangeException() 511 { 512 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MaxValue.AddTicks(1)); 513 AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => DateTimeOffset.MinValue.AddTicks(-1)); 514 } 515 516 [Fact] ToFromFileTime()517 public static void ToFromFileTime() 518 { 519 var today = new DateTimeOffset(DateTime.Today); 520 521 long dateTimeRaw = today.ToFileTime(); 522 Assert.Equal(today, DateTimeOffset.FromFileTime(dateTimeRaw)); 523 } 524 525 [Fact] UtcDateTime()526 public static void UtcDateTime() 527 { 528 DateTime now = DateTime.Now; 529 var dateTimeOffset = new DateTimeOffset(now); 530 Assert.Equal(DateTime.Today, dateTimeOffset.Date); 531 Assert.Equal(now, dateTimeOffset.DateTime); 532 Assert.Equal(now.ToUniversalTime(), dateTimeOffset.UtcDateTime); 533 } 534 535 [Fact] UtcNow()536 public static void UtcNow() 537 { 538 DateTimeOffset start = DateTimeOffset.UtcNow; 539 Assert.True( 540 SpinWait.SpinUntil(() => DateTimeOffset.UtcNow > start, TimeSpan.FromSeconds(30)), 541 "Expected UtcNow to changes"); 542 } 543 544 [Fact] DayOfYear()545 public static void DayOfYear() 546 { 547 DateTimeOffset dateTimeOffset = new DateTimeOffset(); 548 Assert.Equal(dateTimeOffset.DateTime.DayOfYear, dateTimeOffset.DayOfYear); 549 } 550 551 [Fact] DayOfWeekTest()552 public static void DayOfWeekTest() 553 { 554 DateTimeOffset dateTimeOffset = new DateTimeOffset(); 555 Assert.Equal(dateTimeOffset.DateTime.DayOfWeek, dateTimeOffset.DayOfWeek); 556 } 557 558 [Fact] TimeOfDay()559 public static void TimeOfDay() 560 { 561 DateTimeOffset dateTimeOffset = new DateTimeOffset(); 562 Assert.Equal(dateTimeOffset.DateTime.TimeOfDay, dateTimeOffset.TimeOfDay); 563 } 564 UnixTime_TestData()565 private static IEnumerable<object[]> UnixTime_TestData() 566 { 567 yield return new object[] { TestTime.FromMilliseconds(DateTimeOffset.MinValue, -62135596800000) }; 568 yield return new object[] { TestTime.FromMilliseconds(DateTimeOffset.MaxValue, 253402300799999) }; 569 yield return new object[] { TestTime.FromMilliseconds(new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero), 0) }; 570 yield return new object[] { TestTime.FromMilliseconds(new DateTimeOffset(2014, 6, 13, 17, 21, 50, TimeSpan.Zero), 1402680110000) }; 571 yield return new object[] { TestTime.FromMilliseconds(new DateTimeOffset(2830, 12, 15, 1, 23, 45, TimeSpan.Zero), 27169089825000) }; 572 yield return new object[] { TestTime.FromMilliseconds(new DateTimeOffset(2830, 12, 15, 1, 23, 45, 399, TimeSpan.Zero), 27169089825399) }; 573 yield return new object[] { TestTime.FromMilliseconds(new DateTimeOffset(9999, 12, 30, 23, 24, 25, TimeSpan.Zero), 253402212265000) }; 574 yield return new object[] { TestTime.FromMilliseconds(new DateTimeOffset(1907, 7, 7, 7, 7, 7, TimeSpan.Zero), -1971967973000) }; 575 yield return new object[] { TestTime.FromMilliseconds(new DateTimeOffset(1907, 7, 7, 7, 7, 7, 1, TimeSpan.Zero), -1971967972999) }; 576 yield return new object[] { TestTime.FromMilliseconds(new DateTimeOffset(1907, 7, 7, 7, 7, 7, 777, TimeSpan.Zero), -1971967972223) }; 577 yield return new object[] { TestTime.FromMilliseconds(new DateTimeOffset(601636288270011234, TimeSpan.Zero), -1971967972999) }; 578 } 579 580 [Theory] 581 [MemberData(nameof(UnixTime_TestData))] ToUnixTimeMilliseconds(TestTime test)582 public static void ToUnixTimeMilliseconds(TestTime test) 583 { 584 long expectedMilliseconds = test.UnixTimeMilliseconds; 585 long actualMilliseconds = test.DateTimeOffset.ToUnixTimeMilliseconds(); 586 Assert.Equal(expectedMilliseconds, actualMilliseconds); 587 } 588 589 [Theory] 590 [MemberData(nameof(UnixTime_TestData))] ToUnixTimeMilliseconds_RoundTrip(TestTime test)591 public static void ToUnixTimeMilliseconds_RoundTrip(TestTime test) 592 { 593 long unixTimeMilliseconds = test.DateTimeOffset.ToUnixTimeMilliseconds(); 594 FromUnixTimeMilliseconds(TestTime.FromMilliseconds(test.DateTimeOffset, unixTimeMilliseconds)); 595 } 596 597 [Theory] 598 [MemberData(nameof(UnixTime_TestData))] ToUnixTimeSeconds(TestTime test)599 public static void ToUnixTimeSeconds(TestTime test) 600 { 601 long expectedSeconds = test.UnixTimeSeconds; 602 long actualSeconds = test.DateTimeOffset.ToUnixTimeSeconds(); 603 Assert.Equal(expectedSeconds, actualSeconds); 604 } 605 606 [Theory] 607 [MemberData(nameof(UnixTime_TestData))] ToUnixTimeSeconds_RoundTrip(TestTime test)608 public static void ToUnixTimeSeconds_RoundTrip(TestTime test) 609 { 610 long unixTimeSeconds = test.DateTimeOffset.ToUnixTimeSeconds(); 611 FromUnixTimeSeconds(TestTime.FromSeconds(test.DateTimeOffset, unixTimeSeconds)); 612 } 613 614 [Theory] 615 [MemberData(nameof(UnixTime_TestData))] FromUnixTimeMilliseconds(TestTime test)616 public static void FromUnixTimeMilliseconds(TestTime test) 617 { 618 // Only assert that expected == actual up to millisecond precision for conversion from milliseconds 619 long expectedTicks = (test.DateTimeOffset.UtcTicks / TimeSpan.TicksPerMillisecond) * TimeSpan.TicksPerMillisecond; 620 long actualTicks = DateTimeOffset.FromUnixTimeMilliseconds(test.UnixTimeMilliseconds).UtcTicks; 621 Assert.Equal(expectedTicks, actualTicks); 622 } 623 624 [Fact] FromUnixTimeMilliseconds_Invalid()625 public static void FromUnixTimeMilliseconds_Invalid() 626 { 627 AssertExtensions.Throws<ArgumentOutOfRangeException>("milliseconds", () => DateTimeOffset.FromUnixTimeMilliseconds(-62135596800001)); // Milliseconds < DateTimeOffset.MinValue 628 AssertExtensions.Throws<ArgumentOutOfRangeException>("milliseconds", () => DateTimeOffset.FromUnixTimeMilliseconds(253402300800000)); // Milliseconds > DateTimeOffset.MaxValue 629 630 AssertExtensions.Throws<ArgumentOutOfRangeException>("milliseconds", () => DateTimeOffset.FromUnixTimeMilliseconds(long.MinValue)); // Milliseconds < DateTimeOffset.MinValue 631 AssertExtensions.Throws<ArgumentOutOfRangeException>("milliseconds", () => DateTimeOffset.FromUnixTimeMilliseconds(long.MaxValue)); // Milliseconds > DateTimeOffset.MaxValue 632 } 633 634 [Theory] 635 [MemberData(nameof(UnixTime_TestData))] FromUnixTimeSeconds(TestTime test)636 public static void FromUnixTimeSeconds(TestTime test) 637 { 638 // Only assert that expected == actual up to second precision for conversion from seconds 639 long expectedTicks = (test.DateTimeOffset.UtcTicks / TimeSpan.TicksPerSecond) * TimeSpan.TicksPerSecond; 640 long actualTicks = DateTimeOffset.FromUnixTimeSeconds(test.UnixTimeSeconds).UtcTicks; 641 Assert.Equal(expectedTicks, actualTicks); 642 } 643 644 [Fact] FromUnixTimeSeconds_Invalid()645 public static void FromUnixTimeSeconds_Invalid() 646 { 647 AssertExtensions.Throws<ArgumentOutOfRangeException>("seconds", () => DateTimeOffset.FromUnixTimeSeconds(-62135596801));// Seconds < DateTimeOffset.MinValue 648 AssertExtensions.Throws<ArgumentOutOfRangeException>("seconds", () => DateTimeOffset.FromUnixTimeSeconds(253402300800)); // Seconds > DateTimeOffset.MaxValue 649 650 AssertExtensions.Throws<ArgumentOutOfRangeException>("seconds", () => DateTimeOffset.FromUnixTimeSeconds(long.MinValue)); // Seconds < DateTimeOffset.MinValue 651 AssertExtensions.Throws<ArgumentOutOfRangeException>("seconds", () => DateTimeOffset.FromUnixTimeSeconds(long.MaxValue)); // Seconds < DateTimeOffset.MinValue 652 } 653 654 [Theory] 655 [MemberData(nameof(UnixTime_TestData))] FromUnixTimeMilliseconds_RoundTrip(TestTime test)656 public static void FromUnixTimeMilliseconds_RoundTrip(TestTime test) 657 { 658 DateTimeOffset dateTime = DateTimeOffset.FromUnixTimeMilliseconds(test.UnixTimeMilliseconds); 659 ToUnixTimeMilliseconds(TestTime.FromMilliseconds(dateTime, test.UnixTimeMilliseconds)); 660 } 661 662 [Theory] 663 [MemberData(nameof(UnixTime_TestData))] FromUnixTimeSeconds_RoundTrip(TestTime test)664 public static void FromUnixTimeSeconds_RoundTrip(TestTime test) 665 { 666 DateTimeOffset dateTime = DateTimeOffset.FromUnixTimeSeconds(test.UnixTimeSeconds); 667 ToUnixTimeSeconds(TestTime.FromSeconds(dateTime, test.UnixTimeSeconds)); 668 } 669 670 [Fact] ToLocalTime()671 public static void ToLocalTime() 672 { 673 DateTimeOffset dateTimeOffset = new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)); 674 Assert.Equal(new DateTimeOffset(dateTimeOffset.UtcDateTime.ToLocalTime()), dateTimeOffset.ToLocalTime()); 675 } 676 Equals_TestData()677 public static IEnumerable<object[]> Equals_TestData() 678 { 679 yield return new object[] { DateTimeOffset.MinValue, DateTimeOffset.MinValue, true, true }; 680 yield return new object[] { DateTimeOffset.MinValue, DateTimeOffset.MaxValue, false, false }; 681 682 yield return new object[] { DateTimeOffset.Now, new object(), false, false }; 683 yield return new object[] { DateTimeOffset.Now, null, false, false }; 684 } 685 686 [Theory] 687 [MemberData(nameof(Equals_TestData))] Equals(DateTimeOffset dateTimeOffset1, object obj, bool expectedEquals, bool expectedEqualsExact)688 public static void Equals(DateTimeOffset dateTimeOffset1, object obj, bool expectedEquals, bool expectedEqualsExact) 689 { 690 Assert.Equal(expectedEquals, dateTimeOffset1.Equals(obj)); 691 if (obj is DateTimeOffset) 692 { 693 DateTimeOffset dateTimeOffset2 = (DateTimeOffset)obj; 694 Assert.Equal(expectedEquals, dateTimeOffset1.Equals(dateTimeOffset2)); 695 Assert.Equal(expectedEquals, DateTimeOffset.Equals(dateTimeOffset1, dateTimeOffset2)); 696 697 Assert.Equal(expectedEquals, dateTimeOffset1.GetHashCode().Equals(dateTimeOffset2.GetHashCode())); 698 Assert.Equal(expectedEqualsExact, dateTimeOffset1.EqualsExact(dateTimeOffset2)); 699 700 Assert.Equal(expectedEquals, dateTimeOffset1 == dateTimeOffset2); 701 Assert.Equal(!expectedEquals, dateTimeOffset1 != dateTimeOffset2); 702 } 703 } 704 Compare_TestData()705 public static IEnumerable<object[]> Compare_TestData() 706 { 707 yield return new object[] { new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)), new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)), 0 }; 708 yield return new object[] { new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)), new DateTimeOffset(new DateTime(1001, DateTimeKind.Utc)), -1 }; 709 yield return new object[] { new DateTimeOffset(new DateTime(1000, DateTimeKind.Utc)), new DateTimeOffset(new DateTime(999, DateTimeKind.Utc)), 1 }; 710 } 711 712 [Theory] 713 [MemberData(nameof(Compare_TestData))] Compare(DateTimeOffset dateTimeOffset1, DateTimeOffset dateTimeOffset2, int expected)714 public static void Compare(DateTimeOffset dateTimeOffset1, DateTimeOffset dateTimeOffset2, int expected) 715 { 716 Assert.Equal(expected, Math.Sign(dateTimeOffset1.CompareTo(dateTimeOffset2))); 717 Assert.Equal(expected, Math.Sign(DateTimeOffset.Compare(dateTimeOffset1, dateTimeOffset2))); 718 719 IComparable comparable = dateTimeOffset1; 720 Assert.Equal(expected, Math.Sign(comparable.CompareTo(dateTimeOffset2))); 721 722 if (expected > 0) 723 { 724 Assert.True(dateTimeOffset1 > dateTimeOffset2); 725 Assert.Equal(expected >= 0, dateTimeOffset1 >= dateTimeOffset2); 726 Assert.False(dateTimeOffset1 < dateTimeOffset2); 727 Assert.Equal(expected == 0, dateTimeOffset1 <= dateTimeOffset2); 728 } 729 else if (expected < 0) 730 { 731 Assert.False(dateTimeOffset1 > dateTimeOffset2); 732 Assert.Equal(expected == 0, dateTimeOffset1 >= dateTimeOffset2); 733 Assert.True(dateTimeOffset1 < dateTimeOffset2); 734 Assert.Equal(expected <= 0, dateTimeOffset1 <= dateTimeOffset2); 735 } 736 else if (expected == 0) 737 { 738 Assert.False(dateTimeOffset1 > dateTimeOffset2); 739 Assert.True(dateTimeOffset1 >= dateTimeOffset2); 740 Assert.False(dateTimeOffset1 < dateTimeOffset2); 741 Assert.True(dateTimeOffset1 <= dateTimeOffset2); 742 } 743 } 744 745 [Fact] Parse_String()746 public static void Parse_String() 747 { 748 DateTimeOffset expected = DateTimeOffset.MaxValue; 749 string expectedString = expected.ToString(); 750 751 DateTimeOffset result = DateTimeOffset.Parse(expectedString); 752 Assert.Equal(expectedString, result.ToString()); 753 } 754 755 [Fact] Parse_String_FormatProvider()756 public static void Parse_String_FormatProvider() 757 { 758 DateTimeOffset expected = DateTimeOffset.MaxValue; 759 string expectedString = expected.ToString(); 760 761 DateTimeOffset result = DateTimeOffset.Parse(expectedString, null); 762 Assert.Equal(expectedString, result.ToString((IFormatProvider)null)); 763 } 764 765 [Fact] Parse_String_FormatProvider_DateTimeStyles()766 public static void Parse_String_FormatProvider_DateTimeStyles() 767 { 768 DateTimeOffset expected = DateTimeOffset.MaxValue; 769 string expectedString = expected.ToString(); 770 771 DateTimeOffset result = DateTimeOffset.Parse(expectedString, null, DateTimeStyles.None); 772 Assert.Equal(expectedString, result.ToString()); 773 } 774 775 [Fact] Parse_Japanese()776 public static void Parse_Japanese() 777 { 778 var expected = new DateTimeOffset(new DateTime(2012, 12, 21, 10, 8, 6)); 779 var cultureInfo = new CultureInfo("ja-JP"); 780 781 string expectedString = string.Format(cultureInfo, "{0}", expected); 782 Assert.Equal(expected, DateTimeOffset.Parse(expectedString, cultureInfo)); 783 } 784 785 [Fact] TryParse_String()786 public static void TryParse_String() 787 { 788 DateTimeOffset expected = DateTimeOffset.MaxValue; 789 string expectedString = expected.ToString("u"); 790 791 DateTimeOffset result; 792 Assert.True(DateTimeOffset.TryParse(expectedString, out result)); 793 Assert.Equal(expectedString, result.ToString("u")); 794 } 795 796 [Fact] TryParse_String_FormatProvider_DateTimeStyles_U()797 public static void TryParse_String_FormatProvider_DateTimeStyles_U() 798 { 799 DateTimeOffset expected = DateTimeOffset.MaxValue; 800 string expectedString = expected.ToString("u"); 801 802 DateTimeOffset result; 803 Assert.True(DateTimeOffset.TryParse(expectedString, null, DateTimeStyles.None, out result)); 804 Assert.Equal(expectedString, result.ToString("u")); 805 } 806 807 [Fact] TryParse_String_FormatProvider_DateTimeStyles_G()808 public static void TryParse_String_FormatProvider_DateTimeStyles_G() 809 { 810 DateTimeOffset expected = DateTimeOffset.MaxValue; 811 string expectedString = expected.ToString("g"); 812 813 DateTimeOffset result; 814 Assert.True(DateTimeOffset.TryParse(expectedString, null, DateTimeStyles.AssumeUniversal, out result)); 815 Assert.Equal(expectedString, result.ToString("g")); 816 } 817 818 [Fact] 819 [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "The full .NET framework has a bug and incorrectly parses this date")] TryParse_TimeDesignators_NetCore()820 public static void TryParse_TimeDesignators_NetCore() 821 { 822 DateTimeOffset result; 823 Assert.True(DateTimeOffset.TryParse("4/21 5am", new CultureInfo("en-US"), DateTimeStyles.None, out result)); 824 Assert.Equal(4, result.Month); 825 Assert.Equal(21, result.Day); 826 Assert.Equal(5, result.Hour); 827 Assert.Equal(0, result.Minute); 828 Assert.Equal(0, result.Second); 829 830 Assert.True(DateTimeOffset.TryParse("4/21 5pm", new CultureInfo("en-US"), DateTimeStyles.None, out result)); 831 Assert.Equal(4, result.Month); 832 Assert.Equal(21, result.Day); 833 Assert.Equal(17, result.Hour); 834 Assert.Equal(0, result.Minute); 835 Assert.Equal(0, result.Second); 836 } 837 838 [Fact] 839 [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework, "The coreclr fixed a bug where the .NET framework incorrectly parses this date")] TryParse_TimeDesignators_Netfx()840 public static void TryParse_TimeDesignators_Netfx() 841 { 842 DateTimeOffset result; 843 Assert.True(DateTimeOffset.TryParse("4/21 5am", new CultureInfo("en-US"), DateTimeStyles.None, out result)); 844 Assert.Equal(DateTimeOffset.Now.Month, result.Month); 845 Assert.Equal(DateTimeOffset.Now.Day, result.Day); 846 Assert.Equal(4, result.Hour); 847 Assert.Equal(0, result.Minute); 848 Assert.Equal(0, result.Second); 849 850 Assert.True(DateTimeOffset.TryParse("4/21 5pm", new CultureInfo("en-US"), DateTimeStyles.None, out result)); 851 Assert.Equal(DateTimeOffset.Now.Month, result.Month); 852 Assert.Equal(DateTimeOffset.Now.Day, result.Day); 853 Assert.Equal(16, result.Hour); 854 Assert.Equal(0, result.Minute); 855 Assert.Equal(0, result.Second); 856 } 857 858 [Fact] ParseExact_String_String_FormatProvider()859 public static void ParseExact_String_String_FormatProvider() 860 { 861 DateTimeOffset expected = DateTimeOffset.MaxValue; 862 string expectedString = expected.ToString("u"); 863 864 DateTimeOffset result = DateTimeOffset.ParseExact(expectedString, "u", null); 865 Assert.Equal(expectedString, result.ToString("u")); 866 } 867 868 [Fact] ParseExact_String_String_FormatProvider_DateTimeStyles_U()869 public static void ParseExact_String_String_FormatProvider_DateTimeStyles_U() 870 { 871 DateTimeOffset expected = DateTimeOffset.MaxValue; 872 string expectedString = expected.ToString("u"); 873 874 DateTimeOffset result = DateTimeOffset.ParseExact(expectedString, "u", null, DateTimeStyles.None); 875 Assert.Equal(expectedString, result.ToString("u")); 876 } 877 878 [Fact] ParseExact_String_String_FormatProvider_DateTimeStyles_G()879 public static void ParseExact_String_String_FormatProvider_DateTimeStyles_G() 880 { 881 DateTimeOffset expected = DateTimeOffset.MaxValue; 882 string expectedString = expected.ToString("g"); 883 884 DateTimeOffset result = DateTimeOffset.ParseExact(expectedString, "g", null, DateTimeStyles.AssumeUniversal); 885 Assert.Equal(expectedString, result.ToString("g")); 886 } 887 888 [Theory, MemberData(nameof(Format_String_TestData_O))] ParseExact_String_String_FormatProvider_DateTimeStyles_O(DateTimeOffset dt, string expected)889 public static void ParseExact_String_String_FormatProvider_DateTimeStyles_O(DateTimeOffset dt, string expected) 890 { 891 string actual = dt.ToString("o"); 892 Assert.Equal(expected, actual); 893 894 DateTimeOffset result = DateTimeOffset.ParseExact(actual, "o", null, DateTimeStyles.None); 895 Assert.Equal(expected, result.ToString("o")); 896 } 897 Format_String_TestData_O()898 public static IEnumerable<object[]> Format_String_TestData_O() 899 { 900 yield return new object[] { DateTimeOffset.MaxValue, "9999-12-31T23:59:59.9999999+00:00" }; 901 yield return new object[] { DateTimeOffset.MinValue, "0001-01-01T00:00:00.0000000+00:00" }; 902 yield return new object[] { new DateTimeOffset(1906, 8, 15, 7, 24, 5, 300, new TimeSpan(0, 0, 0)), "1906-08-15T07:24:05.3000000+00:00" }; 903 yield return new object[] { new DateTimeOffset(1906, 8, 15, 7, 24, 5, 300, new TimeSpan(7, 30, 0)), "1906-08-15T07:24:05.3000000+07:30" }; 904 } 905 906 [Theory, MemberData(nameof(Format_String_TestData_R))] ParseExact_String_String_FormatProvider_DateTimeStyles_R(DateTimeOffset dt, string expected)907 public static void ParseExact_String_String_FormatProvider_DateTimeStyles_R(DateTimeOffset dt, string expected) 908 { 909 string actual = dt.ToString("r"); 910 Assert.Equal(expected, actual); 911 912 DateTimeOffset result = DateTimeOffset.ParseExact(actual, "r", null, DateTimeStyles.None); 913 Assert.Equal(expected, result.ToString("r")); 914 } 915 Format_String_TestData_R()916 public static IEnumerable<object[]> Format_String_TestData_R() 917 { 918 yield return new object[] { DateTimeOffset.MaxValue, "Fri, 31 Dec 9999 23:59:59 GMT" }; 919 yield return new object[] { DateTimeOffset.MinValue, "Mon, 01 Jan 0001 00:00:00 GMT" }; 920 yield return new object[] { new DateTimeOffset(1906, 8, 15, 7, 24, 5, 300, new TimeSpan(0, 0, 0)), "Wed, 15 Aug 1906 07:24:05 GMT" }; 921 yield return new object[] { new DateTimeOffset(1906, 8, 15, 7, 24, 5, 300, new TimeSpan(7, 30, 0)), "Tue, 14 Aug 1906 23:54:05 GMT" }; 922 } 923 924 [Fact] ParseExact_String_String_FormatProvider_DateTimeStyles_R()925 public static void ParseExact_String_String_FormatProvider_DateTimeStyles_R() 926 { 927 DateTimeOffset expected = DateTimeOffset.MaxValue; 928 string expectedString = expected.ToString("r"); 929 930 DateTimeOffset result = DateTimeOffset.ParseExact(expectedString, "r", null, DateTimeStyles.None); 931 Assert.Equal(expectedString, result.ToString("r")); 932 } 933 934 [Fact] ParseExact_String_String_FormatProvider_DateTimeStyles_CustomFormatProvider()935 public static void ParseExact_String_String_FormatProvider_DateTimeStyles_CustomFormatProvider() 936 { 937 var formatter = new MyFormatter(); 938 string dateBefore = DateTime.Now.ToString(); 939 940 DateTimeOffset dateAfter = DateTimeOffset.ParseExact(dateBefore, "G", formatter, DateTimeStyles.AssumeUniversal); 941 Assert.Equal(dateBefore, dateAfter.DateTime.ToString()); 942 } 943 944 [Fact] ParseExact_String_StringArray_FormatProvider_DateTimeStyles()945 public static void ParseExact_String_StringArray_FormatProvider_DateTimeStyles() 946 { 947 DateTimeOffset expected = DateTimeOffset.MaxValue; 948 string expectedString = expected.ToString("g"); 949 950 var formats = new string[] { "g" }; 951 DateTimeOffset result = DateTimeOffset.ParseExact(expectedString, formats, null, DateTimeStyles.AssumeUniversal); 952 Assert.Equal(expectedString, result.ToString("g")); 953 } 954 955 [Fact] TryParseExact_String_String_FormatProvider_DateTimeStyles_NullFormatProvider()956 public static void TryParseExact_String_String_FormatProvider_DateTimeStyles_NullFormatProvider() 957 { 958 DateTimeOffset expected = DateTimeOffset.MaxValue; 959 string expectedString = expected.ToString("g"); 960 961 DateTimeOffset resulted; 962 Assert.True(DateTimeOffset.TryParseExact(expectedString, "g", null, DateTimeStyles.AssumeUniversal, out resulted)); 963 Assert.Equal(expectedString, resulted.ToString("g")); 964 } 965 966 [Fact] TryParseExact_String_StringArray_FormatProvider_DateTimeStyles()967 public static void TryParseExact_String_StringArray_FormatProvider_DateTimeStyles() 968 { 969 DateTimeOffset expected = DateTimeOffset.MaxValue; 970 string expectedString = expected.ToString("g"); 971 972 var formats = new string[] { "g" }; 973 DateTimeOffset result; 974 Assert.True(DateTimeOffset.TryParseExact(expectedString, formats, null, DateTimeStyles.AssumeUniversal, out result)); 975 Assert.Equal(expectedString, result.ToString("g")); 976 } 977 978 [Theory] 979 [InlineData(~(DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.AllowInnerWhite | DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeLocal | DateTimeStyles.AssumeUniversal | DateTimeStyles.RoundtripKind))] 980 [InlineData(DateTimeStyles.NoCurrentDateDefault)] Parse_InvalidDateTimeStyle_ThrowsArgumentException(DateTimeStyles style)981 public static void Parse_InvalidDateTimeStyle_ThrowsArgumentException(DateTimeStyles style) 982 { 983 AssertExtensions.Throws<ArgumentException>("styles", () => DateTimeOffset.Parse("06/08/1990", null, style)); 984 AssertExtensions.Throws<ArgumentException>("styles", () => DateTimeOffset.ParseExact("06/08/1990", "Y", null, style)); 985 986 DateTimeOffset dateTimeOffset = default(DateTimeOffset); 987 AssertExtensions.Throws<ArgumentException>("styles", () => DateTimeOffset.TryParse("06/08/1990", null, style, out dateTimeOffset)); 988 Assert.Equal(default(DateTimeOffset), dateTimeOffset); 989 990 AssertExtensions.Throws<ArgumentException>("styles", () => DateTimeOffset.TryParseExact("06/08/1990", "Y", null, style, out dateTimeOffset)); 991 Assert.Equal(default(DateTimeOffset), dateTimeOffset); 992 } 993 VerifyDateTimeOffset(DateTimeOffset dateTimeOffset, int year, int month, int day, int hour, int minute, int second, int millisecond, TimeSpan? offset)994 private static void VerifyDateTimeOffset(DateTimeOffset dateTimeOffset, int year, int month, int day, int hour, int minute, int second, int millisecond, TimeSpan? offset) 995 { 996 Assert.Equal(year, dateTimeOffset.Year); 997 Assert.Equal(month, dateTimeOffset.Month); 998 Assert.Equal(day, dateTimeOffset.Day); 999 Assert.Equal(hour, dateTimeOffset.Hour); 1000 Assert.Equal(minute, dateTimeOffset.Minute); 1001 Assert.Equal(second, dateTimeOffset.Second); 1002 Assert.Equal(millisecond, dateTimeOffset.Millisecond); 1003 1004 if (offset.HasValue) 1005 { 1006 Assert.Equal(offset.Value, dateTimeOffset.Offset); 1007 } 1008 } 1009 1010 private class MyFormatter : IFormatProvider 1011 { GetFormat(Type formatType)1012 public object GetFormat(Type formatType) 1013 { 1014 return typeof(IFormatProvider) == formatType ? this : null; 1015 } 1016 } 1017 1018 public class TestTime 1019 { TestTime(DateTimeOffset dateTimeOffset, long unixTimeMilliseconds, long unixTimeSeconds)1020 private TestTime(DateTimeOffset dateTimeOffset, long unixTimeMilliseconds, long unixTimeSeconds) 1021 { 1022 DateTimeOffset = dateTimeOffset; 1023 UnixTimeMilliseconds = unixTimeMilliseconds; 1024 UnixTimeSeconds = unixTimeSeconds; 1025 } 1026 FromMilliseconds(DateTimeOffset dateTimeOffset, long unixTimeMilliseconds)1027 public static TestTime FromMilliseconds(DateTimeOffset dateTimeOffset, long unixTimeMilliseconds) 1028 { 1029 long unixTimeSeconds = unixTimeMilliseconds / 1000; 1030 1031 // Always round UnixTimeSeconds down toward 1/1/0001 00:00:00 1032 // (this happens automatically for unixTimeMilliseconds > 0) 1033 bool hasSubSecondPrecision = unixTimeMilliseconds % 1000 != 0; 1034 if (unixTimeMilliseconds < 0 && hasSubSecondPrecision) 1035 { 1036 --unixTimeSeconds; 1037 } 1038 1039 return new TestTime(dateTimeOffset, unixTimeMilliseconds, unixTimeSeconds); 1040 } 1041 FromSeconds(DateTimeOffset dateTimeOffset, long unixTimeSeconds)1042 public static TestTime FromSeconds(DateTimeOffset dateTimeOffset, long unixTimeSeconds) 1043 { 1044 return new TestTime(dateTimeOffset, unixTimeSeconds * 1000, unixTimeSeconds); 1045 } 1046 1047 public DateTimeOffset DateTimeOffset { get; private set; } 1048 public long UnixTimeMilliseconds { get; private set; } 1049 public long UnixTimeSeconds { get; private set; } 1050 } 1051 1052 [Fact] Ctor_Calendar_TimeSpan()1053 public static void Ctor_Calendar_TimeSpan() 1054 { 1055 var dateTimeOffset = new DateTimeOffset(1, 1, 1, 0, 0, 0, 0, new GregorianCalendar(),TimeSpan.Zero); 1056 VerifyDateTimeOffset(dateTimeOffset, 1, 1, 1, 0, 0, 0, 0, TimeSpan.Zero); 1057 } 1058 } 1059 } 1060