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