diff --git a/NewLife.Core/Common/Utility.cs b/NewLife.Core/Common/Utility.cs index 0269178bd..74fad9f0e 100644 --- a/NewLife.Core/Common/Utility.cs +++ b/NewLife.Core/Common/Utility.cs @@ -91,13 +91,13 @@ public static class Utility /// public static DateTimeOffset ToDateTimeOffset(this Object? value, DateTimeOffset defaultValue) => Convert.ToDateTimeOffset(value, defaultValue); - /// 去掉时间日期指定位置后面部分,可指定毫秒ms、秒s、分m、小时h + /// 去掉时间日期指定位置后面部分,可指定毫秒ms、秒s、分m、小时h、纳秒ns /// 时间日期 /// 格式字符串,默认s格式化到秒,ms格式化到毫秒 /// public static DateTime Trim(this DateTime value, String format = "s") => Convert.Trim(value, format); - /// 去掉时间日期指定位置后面部分,可指定毫秒ms、秒s、分m、小时h + /// 去掉时间日期指定位置后面部分,可指定毫秒ms、秒s、分m、小时h、纳秒ns /// 时间日期 /// 格式字符串,默认s格式化到秒,ms格式化到毫秒 /// @@ -556,7 +556,7 @@ public virtual DateTime ToDateTime(Object? value, DateTime defaultValue) // 处理UTC var utc = false; - if (str.EndsWithIgnoreCase(" UTC")) + if (str.EndsWithIgnoreCase(" UTC") || str.EndsWith("Z") && str.Contains('T')) { utc = true; str = str[0..^4]; @@ -702,7 +702,7 @@ private static Int32 TrimNumber(ReadOnlySpan input, Span output) return idx; } - /// 去掉时间日期指定位置后面部分,可指定毫秒ms、秒s、分m、小时h + /// 去掉时间日期指定位置后面部分,可指定毫秒ms、秒s、分m、小时h、纳秒ns /// 时间日期 /// 格式字符串,默认s格式化到秒,ms格式化到毫秒 /// @@ -712,6 +712,7 @@ public virtual DateTime Trim(DateTime value, String format) { #if NET7_0_OR_GREATER "us" => new DateTime(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second, value.Millisecond, value.Microsecond, value.Kind), + "ns" => new DateTime(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second, value.Millisecond, value.Microsecond / 100 * 100, value.Kind), #endif "ms" => new DateTime(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second, value.Millisecond, value.Kind), "s" => new DateTime(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second, value.Kind), diff --git a/XUnitTest.Core/Common/UtilityTests.cs b/XUnitTest.Core/Common/UtilityTests.cs index 1a4fa6f0f..916ac45d0 100644 --- a/XUnitTest.Core/Common/UtilityTests.cs +++ b/XUnitTest.Core/Common/UtilityTests.cs @@ -13,13 +13,26 @@ public void BasicTest() Assert.Equal(DateTimeKind.Local, dt.Kind); Assert.Equal(dt.ToString("yyyy-MM-dd HH:mm:ss"), dt.ToFullString()); Assert.Equal(dt.ToString("yyyy-MM-dd HH:mm:ss.fff"), dt.ToFullString(true)); + var dt_ = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second); + Assert.Equal(DateTimeKind.Unspecified, dt_.Kind); Assert.Equal(dt.Trim(), dt_); - Assert.Equal(dt.Trim(), dt.ToFullString().ToDateTime()); - Assert.Equal(dt.Trim(), dt.ToInt().ToDateTime()); + + var dt2 = dt.ToFullString().ToDateTime(); + Assert.Equal(DateTimeKind.Unspecified, dt2.Kind); + Assert.Equal(dt.Trim(), dt2); + + dt2 = dt.ToInt().ToDateTime(); + Assert.Equal(DateTimeKind.Unspecified, dt2.Kind); + Assert.Equal(dt.Trim(), dt2); + + dt2 = dt.ToLong().ToDateTime(); + Assert.Equal(DateTimeKind.Unspecified, dt2.Kind); Assert.Equal(dt.Trim("ms"), dt.ToLong().ToDateTime()); - Assert.Equal(dt.Trim("m"), dt.ToInt().ToDateTime().AddSeconds(-dt.Second)); - Assert.Equal(dt.Trim("h"), dt.ToInt().ToDateTime().AddSeconds(-dt.Second).AddMinutes(-dt.Minute)); + + dt2 = dt.ToInt().ToDateTime(); + Assert.Equal(dt.Trim("m"), dt2.AddSeconds(-dt2.Second)); + Assert.Equal(dt.Trim("h"), dt2.AddSeconds(-dt2.Second).AddMinutes(-dt2.Minute)); Assert.Empty(DateTime.MinValue.ToFullString("")); Assert.Equal(dt.ToString("yyyy-MM-dd HH:mm:ss"), dt.ToString("", "")); Assert.Empty(DateTime.MinValue.ToString("", "")); @@ -29,7 +42,49 @@ public void BasicTest() var dtU = str.ToDateTime(); Assert.Equal(dt, dtU); Assert.Equal(dt.Kind, dtU.Kind); + } + + [Fact] + public void UtcTest() + { + var dt = DateTime.UtcNow; + Assert.Equal(DateTimeKind.Utc, dt.Kind); + Assert.Equal(dt.ToString("yyyy-MM-dd HH:mm:ss"), dt.ToFullString()); + Assert.Equal(dt.ToString("yyyy-MM-dd HH:mm:ss.fff"), dt.ToFullString(true)); + + var dt_ = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, DateTimeKind.Utc); + Assert.Equal(DateTimeKind.Utc, dt_.Kind); + Assert.Equal(dt.Trim(), dt_); + + var dt2 = dt.ToFullString().ToDateTime(); + Assert.Equal(DateTimeKind.Unspecified, dt2.Kind); + Assert.Equal(dt.Trim(), dt2); + dt2 = dt.ToInt().ToDateTime(); + Assert.Equal(DateTimeKind.Unspecified, dt2.Kind); + Assert.Equal(dt.Trim(), dt2); + + dt2 = dt.ToLong().ToDateTime(); + Assert.Equal(DateTimeKind.Unspecified, dt2.Kind); + Assert.Equal(dt.Trim("ms"), dt.ToLong().ToDateTime()); + + dt2 = dt.ToInt().ToDateTime(); + Assert.Equal(dt.Trim("m"), dt2.AddSeconds(-dt2.Second)); + Assert.Equal(dt.Trim("h"), dt2.AddSeconds(-dt2.Second).AddMinutes(-dt2.Minute)); + Assert.Empty(DateTime.MinValue.ToFullString("")); + Assert.Equal(dt.ToString("yyyy-MM-dd HH:mm:ss"), dt.ToString("", "")); + Assert.Empty(DateTime.MinValue.ToString("", "")); + + var str = dt.ToString("O"); + XTrace.WriteLine(str); + var dtU = str.ToDateTime(); + Assert.Equal(dt.Trim("ns"), dtU); + Assert.Equal(dt.Kind, dtU.Kind); + } + + [Fact] + public void TimeZoneInfoTest() + { var dto = DateTimeOffset.Now; Assert.Equal(dto.ToString("yyyy-MM-dd HH:mm:ss zzz"), dto.ToFullString()); Assert.Equal(dto.ToString("yyyy-MM-dd HH:mm:ss.fff zzz"), dto.ToFullString(true)); @@ -111,6 +166,19 @@ public void DateTimeTest() str = "2022/4/6"; dt = str.ToDateTime(); Assert.Equal(new DateTime(2022, 4, 6), dt); + + var dt1970 = new DateTime(1970, 1, 1); + var dt1970b = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + // DateTime 改变时区后再相减,结果改变;而 DateTimeOffset 不会 + // DateTime 减去目标时间,忽略目标时区,直接减去时间值 + dt = DateTime.UtcNow; + var n1 = (Int32)(dt - dt1970).TotalSeconds; + var n2 = (Int32)(dt.ToLocalTime() - dt1970).TotalSeconds; + var n3 = (Int32)(dt - dt1970b).TotalSeconds; + var n4 = (Int32)(dt.ToLocalTime() - dt1970b).TotalSeconds; + Assert.Equal(n1, n3); + Assert.Equal(n2, n4); } [Fact] @@ -123,6 +191,18 @@ public void DateTimeOffsetTest() str = "2020-03-09T21:16:25.9052764+08:00"; var df = str.ToDateTimeOffset(); Assert.Equal(new DateTimeOffset(2020, 3, 9, 21, 16, 25, 905, TimeSpan.FromHours(8)).AddTicks(2764), df); + + var dt1970 = new DateTimeOffset(new DateTime(1970, 1, 1)); + var dt1970b = new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + + // DateTimeOffset 可以改变时区后再相减,结果不变 + var dto = DateTimeOffset.UtcNow; + var n1 = (Int32)(dto - dt1970).TotalSeconds; + var n2 = (Int32)(dto.ToLocalTime() - dt1970).TotalSeconds; + var n3 = (Int32)(dto - dt1970b).TotalSeconds; + var n4 = (Int32)(dto.ToLocalTime() - dt1970b).TotalSeconds; + Assert.Equal(n1, n2); + Assert.Equal(n3, n4); } [Fact]