From 9f65b732042a3819e2f5ba5092a633e5f68a3cd5 Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Tue, 16 Nov 2021 22:47:53 +0100 Subject: [PATCH] GetAlignedInterval nun in UTC und Local unterschieden (Local beachtet Sommer-/Winterzeit); UnitTests begonnen --- AMWD.Common.Tests/AMWD.Common.Tests.csproj | 18 + .../Extensions/DateTimeExtensionsTests.cs | 318 ++++++++++++++++++ .../Extensions/EnumExtensionsTests.cs | 107 ++++++ .../Utils/CustomMultipleAttribute.cs | 15 + AMWD.Common/Extensions/DateTimeExtensions.cs | 73 ++-- Common.sln | 20 +- 6 files changed, 515 insertions(+), 36 deletions(-) create mode 100644 AMWD.Common.Tests/AMWD.Common.Tests.csproj create mode 100644 AMWD.Common.Tests/Extensions/DateTimeExtensionsTests.cs create mode 100644 AMWD.Common.Tests/Extensions/EnumExtensionsTests.cs create mode 100644 AMWD.Common.Tests/Utils/CustomMultipleAttribute.cs diff --git a/AMWD.Common.Tests/AMWD.Common.Tests.csproj b/AMWD.Common.Tests/AMWD.Common.Tests.csproj new file mode 100644 index 0000000..63f846d --- /dev/null +++ b/AMWD.Common.Tests/AMWD.Common.Tests.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + false + + + + + + + + + + + + + diff --git a/AMWD.Common.Tests/Extensions/DateTimeExtensionsTests.cs b/AMWD.Common.Tests/Extensions/DateTimeExtensionsTests.cs new file mode 100644 index 0000000..c32b41a --- /dev/null +++ b/AMWD.Common.Tests/Extensions/DateTimeExtensionsTests.cs @@ -0,0 +1,318 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace AMWD.Common.Tests.Extensions +{ + [TestClass] + public class DateTimeExtensionsTests + { + [TestMethod] + public void ShouldReturnUtc() + { + // arrange + var utc = new DateTime(2021, 11, 15, 11, 22, 33, DateTimeKind.Utc); + var local = new DateTime(2021, 11, 15, 11, 22, 33, DateTimeKind.Local); + var unspecified = new DateTime(2021, 11, 15, 11, 22, 33, DateTimeKind.Unspecified); + + // act + var utcCorrected = utc.AsUtc(); + var localCorrected = local.AsUtc(); + var unspecifiedCorrected = unspecified.AsUtc(); + + // assert + Assert.AreEqual(DateTimeKind.Utc, utcCorrected.Kind); + Assert.AreEqual(DateTimeKind.Utc, localCorrected.Kind); + Assert.AreEqual(DateTimeKind.Utc, unspecifiedCorrected.Kind); + + Assert.AreEqual(utc, utcCorrected); + Assert.AreEqual(utc.AddHours(-1), localCorrected); + Assert.AreEqual(utc, unspecifiedCorrected); + } + + [TestMethod] + public void ShouldReturnLocal() + { + // arrange + var utc = new DateTime(2021, 11, 15, 11, 22, 33, DateTimeKind.Utc); + var local = new DateTime(2021, 11, 15, 11, 22, 33, DateTimeKind.Local); + var unspecified = new DateTime(2021, 11, 15, 11, 22, 33, DateTimeKind.Unspecified); + + // act + var utcCorrected = utc.AsLocal(); + var localCorrected = local.AsLocal(); + var unspecifiedCorrected = unspecified.AsLocal(); + + // assert + Assert.AreEqual(DateTimeKind.Local, utcCorrected.Kind); + Assert.AreEqual(DateTimeKind.Local, localCorrected.Kind); + Assert.AreEqual(DateTimeKind.Local, unspecifiedCorrected.Kind); + + Assert.AreEqual(local.AddHours(1), utcCorrected); + Assert.AreEqual(local, localCorrected); + Assert.AreEqual(local, unspecifiedCorrected); + } + + [TestMethod] + public void ShouldReturnCorrectUtcAlignmentDaylightSavingEnd() + { + // arrange + var utcNow = new DateTime(2021, 10, 30, 12, 15, 30, 45, DateTimeKind.Utc); + + var intervalThreeSeconds = TimeSpan.FromSeconds(3); + var intervalSixMinutes = TimeSpan.FromMinutes(6); + var intervalTwoHours = TimeSpan.FromHours(2); + var intervalDay = TimeSpan.FromDays(1); + + var offsetTwoMinutes = TimeSpan.FromMinutes(2); + var offsetFourHours = TimeSpan.FromHours(4); + + // act + var diffThreeSeconds = intervalThreeSeconds.GetAlignedInterval(utcNow); + var diffSixMinutes = intervalSixMinutes.GetAlignedInterval(utcNow); + var diffTwoHours = intervalTwoHours.GetAlignedInterval(utcNow); + var diffDay = intervalDay.GetAlignedInterval(utcNow); + + var diffTwoHoursOffset = intervalTwoHours.GetAlignedInterval(utcNow, offsetTwoMinutes); + var diffDayOffset = intervalDay.GetAlignedInterval(utcNow, offsetFourHours); + + // assert + Assert.AreEqual(TimeSpan.Parse("00:00:02.955"), diffThreeSeconds); + Assert.AreEqual(TimeSpan.Parse("00:02:29.955"), diffSixMinutes); + Assert.AreEqual(TimeSpan.Parse("01:44:29.955"), diffTwoHours); + Assert.AreEqual(TimeSpan.Parse("11:44:29.955"), diffDay); + + Assert.AreEqual(TimeSpan.Parse("01:46:29.955"), diffTwoHoursOffset); + Assert.AreEqual(TimeSpan.Parse("15:44:29.955"), diffDayOffset); // must be the same whether daylight saving has ended + } + + [TestMethod] + public void ShouldReturnCorrectUtcAlignmentDaylightSavingStart() + { + // arrange + var utcNow = new DateTime(2022, 3, 26, 12, 15, 30, 45, DateTimeKind.Utc); + + var intervalThreeSeconds = TimeSpan.FromSeconds(3); + var intervalSixMinutes = TimeSpan.FromMinutes(6); + var intervalTwoHours = TimeSpan.FromHours(2); + var intervalDay = TimeSpan.FromDays(1); + + var offsetTwoMinutes = TimeSpan.FromMinutes(2); + var offsetFourHours = TimeSpan.FromHours(4); + + // act + var diffThreeSeconds = intervalThreeSeconds.GetAlignedInterval(utcNow); + var diffSixMinutes = intervalSixMinutes.GetAlignedInterval(utcNow); + var diffTwoHours = intervalTwoHours.GetAlignedInterval(utcNow); + var diffDay = intervalDay.GetAlignedInterval(utcNow); + + var diffTwoHoursOffset = intervalTwoHours.GetAlignedInterval(utcNow, offsetTwoMinutes); + var diffDayOffset = intervalDay.GetAlignedInterval(utcNow, offsetFourHours); + + // assert + Assert.AreEqual(TimeSpan.Parse("00:00:02.955"), diffThreeSeconds); + Assert.AreEqual(TimeSpan.Parse("00:02:29.955"), diffSixMinutes); + Assert.AreEqual(TimeSpan.Parse("01:44:29.955"), diffTwoHours); + Assert.AreEqual(TimeSpan.Parse("11:44:29.955"), diffDay); + + Assert.AreEqual(TimeSpan.Parse("01:46:29.955"), diffTwoHoursOffset); + Assert.AreEqual(TimeSpan.Parse("15:44:29.955"), diffDayOffset); // must be the same whether daylight saving has started + } + + [TestMethod] + public void ShouldReturnCorrectLocalAlignmentDaylightSavingEnd() + { + // arrange + var utcNow = new DateTime(2021, 10, 30, 12, 15, 30, 45, DateTimeKind.Local); + + var intervalThreeSeconds = TimeSpan.FromSeconds(3); + var intervalSixMinutes = TimeSpan.FromMinutes(6); + var intervalTwoHours = TimeSpan.FromHours(2); + var intervalDay = TimeSpan.FromDays(1); + + var offsetTwoMinutes = TimeSpan.FromMinutes(2); + var offsetFourHours = TimeSpan.FromHours(4); + + // act + var diffThreeSeconds = intervalThreeSeconds.GetAlignedInterval(utcNow); + var diffSixMinutes = intervalSixMinutes.GetAlignedInterval(utcNow); + var diffTwoHours = intervalTwoHours.GetAlignedInterval(utcNow); + var diffDay = intervalDay.GetAlignedInterval(utcNow); + + var diffTwoHoursOffset = intervalTwoHours.GetAlignedInterval(utcNow, offsetTwoMinutes); + var diffDayOffset = intervalDay.GetAlignedInterval(utcNow, offsetFourHours); + + // assert + Assert.AreEqual(TimeSpan.Parse("00:00:02.955"), diffThreeSeconds); + Assert.AreEqual(TimeSpan.Parse("00:02:29.955"), diffSixMinutes); + Assert.AreEqual(TimeSpan.Parse("01:44:29.955"), diffTwoHours); + Assert.AreEqual(TimeSpan.Parse("11:44:29.955"), diffDay); + + Assert.AreEqual(TimeSpan.Parse("01:46:29.955"), diffTwoHoursOffset); + Assert.AreEqual(TimeSpan.Parse("14:44:29.955"), diffDayOffset); // has to be minus one hour due to daylight saving ended + } + + [TestMethod] + public void ShouldReturnCorrectLocalAlignmentDaylightSavingStart() + { + // arrange + var utcNow = new DateTime(2022, 3, 26, 12, 15, 30, 45, DateTimeKind.Local); + + var intervalThreeSeconds = TimeSpan.FromSeconds(3); + var intervalSixMinutes = TimeSpan.FromMinutes(6); + var intervalTwoHours = TimeSpan.FromHours(2); + var intervalDay = TimeSpan.FromDays(1); + + var offsetTwoMinutes = TimeSpan.FromMinutes(2); + var offsetFourHours = TimeSpan.FromHours(4); + + // act + var diffThreeSeconds = intervalThreeSeconds.GetAlignedInterval(utcNow); + var diffSixMinutes = intervalSixMinutes.GetAlignedInterval(utcNow); + var diffTwoHours = intervalTwoHours.GetAlignedInterval(utcNow); + var diffDay = intervalDay.GetAlignedInterval(utcNow); + + var diffTwoHoursOffset = intervalTwoHours.GetAlignedInterval(utcNow, offsetTwoMinutes); + var diffDayOffset = intervalDay.GetAlignedInterval(utcNow, offsetFourHours); + + // assert + Assert.AreEqual(TimeSpan.Parse("00:00:02.955"), diffThreeSeconds); + Assert.AreEqual(TimeSpan.Parse("00:02:29.955"), diffSixMinutes); + Assert.AreEqual(TimeSpan.Parse("01:44:29.955"), diffTwoHours); + Assert.AreEqual(TimeSpan.Parse("11:44:29.955"), diffDay); + + Assert.AreEqual(TimeSpan.Parse("01:46:29.955"), diffTwoHoursOffset); + Assert.AreEqual(TimeSpan.Parse("16:44:29.955"), diffDayOffset); // has to be plus one hour due to daylight saving started + } + + [TestMethod] + public void ShouldReturnCorrectShortStringForTimeSpan() + { + // arrange + var timeSpan = TimeSpan.Parse("1.10:11:12.345"); + + // act + string shortString = timeSpan.ToShortString(withMilliseconds: false); + string shortStringWithMillis = timeSpan.ToShortString(withMilliseconds: true); + + // assert + Assert.AreEqual("1d 10h 11m 12s", shortString); + Assert.AreEqual("1d 10h 11m 12s 345ms", shortStringWithMillis); + } + + [TestMethod] + public void ShouldRoundToSecond() + { + // arrange + var timestampUp = new DateTime(2021, 11, 16, 20, 15, 30, 500); + var timestampDown = new DateTime(2021, 11, 16, 20, 15, 30, 499); + + var timespanUp = new TimeSpan(1, 2, 3, 4, 500); + var timespanDown = new TimeSpan(1, 2, 3, 4, 499); + + // act + var timestampUpRounded = timestampUp.RoundToSecond(); + var timestampDownRounded = timestampDown.RoundToSecond(); + + var timespanUpRounded = timespanUp.RoundToSecond(); + var timespanDownRounded = timespanDown.RoundToSecond(); + + // assert + Assert.AreNotEqual(timestampUp, timestampUpRounded); + Assert.AreEqual(DateTime.Parse("2021-11-16 20:15:31.000"), timestampUpRounded); + Assert.AreNotEqual(timestampDown, timestampDownRounded); + Assert.AreEqual(DateTime.Parse("2021-11-16 20:15:30.000"), timestampDownRounded); + + Assert.AreNotEqual(timespanUp, timespanUpRounded); + Assert.AreEqual(TimeSpan.Parse("1.02:03:05.000"), timespanUpRounded); + Assert.AreNotEqual(timespanDown, timespanDownRounded); + Assert.AreEqual(TimeSpan.Parse("1.02:03:04.000"), timespanDownRounded); + } + + [TestMethod] + public void ShouldRoundToMinute() + { + // arrange + var timestampUp = new DateTime(2021, 11, 16, 20, 15, 30, 0); + var timestampDown = new DateTime(2021, 11, 16, 20, 15, 29, 999); + + var timespanUp = new TimeSpan(1, 2, 3, 30, 0); + var timespanDown = new TimeSpan(1, 2, 3, 29, 999); + + // act + var timestampUpRounded = timestampUp.RoundToMinute(); + var timestampDownRounded = timestampDown.RoundToMinute(); + + var timespanUpRounded = timespanUp.RoundToMinute(); + var timespanDownRounded = timespanDown.RoundToMinute(); + + // assert + Assert.AreNotEqual(timestampUp, timestampUpRounded); + Assert.AreEqual(DateTime.Parse("2021-11-16 20:16:00.000"), timestampUpRounded); + Assert.AreNotEqual(timestampDown, timestampDownRounded); + Assert.AreEqual(DateTime.Parse("2021-11-16 20:15:00.000"), timestampDownRounded); + + Assert.AreNotEqual(timespanUp, timespanUpRounded); + Assert.AreEqual(TimeSpan.Parse("1.02:04:00.000"), timespanUpRounded); + Assert.AreNotEqual(timespanDown, timespanDownRounded); + Assert.AreEqual(TimeSpan.Parse("1.02:03:00.000"), timespanDownRounded); + } + + [TestMethod] + public void ShouldRoundToHour() + { + // arrange + var timestampUp = new DateTime(2021, 11, 16, 20, 30, 0, 0); + var timestampDown = new DateTime(2021, 11, 16, 20, 29, 59, 999); + + var timespanUp = new TimeSpan(1, 2, 30, 0, 0); + var timespanDown = new TimeSpan(1, 2, 29, 59, 999); + + // act + var timestampUpRounded = timestampUp.RoundToHour(); + var timestampDownRounded = timestampDown.RoundToHour(); + + var timespanUpRounded = timespanUp.RoundToHour(); + var timespanDownRounded = timespanDown.RoundToHour(); + + // assert + Assert.AreNotEqual(timestampUp, timestampUpRounded); + Assert.AreEqual(DateTime.Parse("2021-11-16 21:00:00.000"), timestampUpRounded); + Assert.AreNotEqual(timestampDown, timestampDownRounded); + Assert.AreEqual(DateTime.Parse("2021-11-16 20:00:00.000"), timestampDownRounded); + + Assert.AreNotEqual(timespanUp, timespanUpRounded); + Assert.AreEqual(TimeSpan.Parse("1.03:00:00.000"), timespanUpRounded); + Assert.AreNotEqual(timespanDown, timespanDownRounded); + Assert.AreEqual(TimeSpan.Parse("1.02:00:00.000"), timespanDownRounded); + } + + [TestMethod] + public void ShouldRoundToDay() + { + // arrange + var timestampUp = new DateTime(2021, 11, 16, 12, 0, 0, 0); + var timestampDown = new DateTime(2021, 11, 16, 11, 59, 59, 999); + + var timespanUp = new TimeSpan(1, 12, 0, 0, 0); + var timespanDown = new TimeSpan(1, 11, 59, 59, 999); + + // act + var timestampUpRounded = timestampUp.RoundToDay(); + var timestampDownRounded = timestampDown.RoundToDay(); + + var timespanUpRounded = timespanUp.RoundToDay(); + var timespanDownRounded = timespanDown.RoundToDay(); + + // assert + Assert.AreNotEqual(timestampUp, timestampUpRounded); + Assert.AreEqual(DateTime.Parse("2021-11-17 00:00:00.000"), timestampUpRounded); + Assert.AreNotEqual(timestampDown, timestampDownRounded); + Assert.AreEqual(DateTime.Parse("2021-11-16 00:00:00.000"), timestampDownRounded); + + Assert.AreNotEqual(timespanUp, timespanUpRounded); + Assert.AreEqual(TimeSpan.Parse("2.00:00:00.000"), timespanUpRounded); + Assert.AreNotEqual(timespanDown, timespanDownRounded); + Assert.AreEqual(TimeSpan.Parse("1.00:00:00.000"), timespanDownRounded); + } + } +} diff --git a/AMWD.Common.Tests/Extensions/EnumExtensionsTests.cs b/AMWD.Common.Tests/Extensions/EnumExtensionsTests.cs new file mode 100644 index 0000000..62f91bc --- /dev/null +++ b/AMWD.Common.Tests/Extensions/EnumExtensionsTests.cs @@ -0,0 +1,107 @@ +using System; +using System.Linq; +using AMWD.Common.Tests.Utils; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using DescriptionAttribute = System.ComponentModel.DescriptionAttribute; + +namespace AMWD.Common.Tests.Extensions +{ + [TestClass] + public class EnumExtensionsTests + { + [TestMethod] + public void ShouldReturnEmptyList() + { + // arrange + var enumValue = TestEnum.Two; + + // act + var customList = enumValue.GetAttributes(); + var descriptionList = enumValue.GetAttributes(); + + // assert + Assert.IsNotNull(customList); + Assert.IsFalse(customList.Any()); + Assert.IsNotNull(descriptionList); + Assert.IsFalse(descriptionList.Any()); + } + + [TestMethod] + public void ShouldReturnList() + { + // arrange + var enumValue = TestEnum.Zero; + + // act + var customList = enumValue.GetAttributes(); + var descriptionList = enumValue.GetAttributes(); + + // assert + Assert.IsNotNull(customList); + Assert.IsTrue(customList.Any()); + Assert.AreEqual(2, customList.Count()); + Assert.IsNotNull(descriptionList); + Assert.IsTrue(descriptionList.Any()); + Assert.AreEqual(1, descriptionList.Count()); + } + + [TestMethod] + public void ShouldReturnNothing() + { + // arrange + var enumValue = TestEnum.Two; + + // act + var customAttribute = enumValue.GetAttribute(); + var descriptionAttribute = enumValue.GetAttribute(); + + // assert + Assert.IsNull(customAttribute); + Assert.IsNull(descriptionAttribute); + } + + [TestMethod] + public void ShouldReturnFirstAttribute() + { + // arrange + var enumValue = TestEnum.Zero; + + // act + var customAttribute = enumValue.GetAttribute(); + var descriptionAttribute = enumValue.GetAttribute(); + + // assert + Assert.IsNotNull(customAttribute); + Assert.AreEqual("nix", customAttribute.Name); + Assert.IsNotNull(descriptionAttribute); + Assert.AreEqual("Null", descriptionAttribute.Description); + } + + [TestMethod] + public void ShouldReturnDescriptionOrStringRepresentation() + { + // arrange + var enumWithDescription = TestEnum.One; + var enumWithoutDescripton = TestEnum.Two; + + // act + string description = enumWithDescription.GetDescription(); + string noDescription = enumWithoutDescripton.GetDescription(); + + // assert + Assert.AreEqual("Eins", description); + Assert.AreEqual(enumWithoutDescripton.ToString(), noDescription); + } + + internal enum TestEnum + { + [CustomMultiple("nix")] + [CustomMultiple("Null")] + [Description("Null")] + Zero, + [Description("Eins")] + One, + Two, + } + } +} diff --git a/AMWD.Common.Tests/Utils/CustomMultipleAttribute.cs b/AMWD.Common.Tests/Utils/CustomMultipleAttribute.cs new file mode 100644 index 0000000..413fae0 --- /dev/null +++ b/AMWD.Common.Tests/Utils/CustomMultipleAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace AMWD.Common.Tests.Utils +{ + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + internal class CustomMultipleAttribute : Attribute + { + public CustomMultipleAttribute(string name) + { + Name = name; + } + + public string Name { get; set; } + } +} diff --git a/AMWD.Common/Extensions/DateTimeExtensions.cs b/AMWD.Common/Extensions/DateTimeExtensions.cs index 7f229d5..dbd554a 100644 --- a/AMWD.Common/Extensions/DateTimeExtensions.cs +++ b/AMWD.Common/Extensions/DateTimeExtensions.cs @@ -1,5 +1,7 @@ using System.Text; +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("AMWD.Common.Tests")] + namespace System { /// @@ -41,23 +43,44 @@ namespace System #endregion Kind + #region Aligned Interval + /// - /// Aligns the to the clock. + /// Aligns the to the UTC clock. /// /// The timespan to align. /// A specific offset to the timespan. /// The timespan until the aligned time. - public static TimeSpan GetAlignedInterval(this TimeSpan timeSpan, TimeSpan offset = default) + public static TimeSpan GetAlignedIntervalUtc(this TimeSpan timeSpan, TimeSpan offset = default) + => timeSpan.GetAlignedInterval(DateTime.UtcNow, offset); + + /// + /// Aligns the to the local clock and respects daylight saving time. + /// + /// The timespan to align. + /// A specific offset to the timespan. + /// The timespan until the aligned time. + public static TimeSpan GetAlignedIntervalLocal(this TimeSpan timeSpan, TimeSpan offset = default) + => timeSpan.GetAlignedInterval(DateTime.Now, offset); + + internal static TimeSpan GetAlignedInterval(this TimeSpan timeSpan, DateTime now, TimeSpan offset = default) { - var now = DateTime.UtcNow; - var nextTime = new DateTime(now.Ticks / timeSpan.Ticks * timeSpan.Ticks) + offset; + var nowWithOffset = new DateTimeOffset(now); - if (nextTime <= now) - nextTime += timeSpan; + var nextTime = new DateTime(nowWithOffset.Ticks / timeSpan.Ticks * timeSpan.Ticks, now.Kind).Add(offset); + var nextTimeWithOffset = new DateTimeOffset(nextTime); - return nextTime - now; + if (nextTimeWithOffset <= nowWithOffset) + nextTimeWithOffset = nextTimeWithOffset.Add(timeSpan); + + if (now.Kind == DateTimeKind.Local) + return nextTimeWithOffset.LocalDateTime - nowWithOffset.LocalDateTime; + + return nextTimeWithOffset - nowWithOffset; } + #endregion Aligned Interval + /// /// Prints the timespan as shortended string. /// @@ -94,9 +117,7 @@ namespace System /// public static DateTime RoundToSecond(this DateTime dt) - { - return new DateTime(RoundTicks(dt.Ticks, TimeSpan.TicksPerSecond), dt.Kind); - } + => new(RoundTicks(dt.Ticks, TimeSpan.TicksPerSecond), dt.Kind); /// /// Rounds the to full minutes. @@ -104,9 +125,7 @@ namespace System /// The time value to round. /// public static DateTime RoundToMinute(this DateTime dt) - { - return new DateTime(RoundTicks(dt.Ticks, TimeSpan.TicksPerMinute), dt.Kind); - } + => new(RoundTicks(dt.Ticks, TimeSpan.TicksPerMinute), dt.Kind); /// /// Rounds the to full hours. @@ -114,9 +133,7 @@ namespace System /// The time value to round. /// public static DateTime RoundToHour(this DateTime dt) - { - return new DateTime(RoundTicks(dt.Ticks, TimeSpan.TicksPerHour), dt.Kind); - } + => new(RoundTicks(dt.Ticks, TimeSpan.TicksPerHour), dt.Kind); /// /// Rounds the to full days. @@ -124,9 +141,7 @@ namespace System /// The time value to round. /// public static DateTime RoundToDay(this DateTime dt) - { - return new DateTime(RoundTicks(dt.Ticks, TimeSpan.TicksPerDay), dt.Kind); - } + => new(RoundTicks(dt.Ticks, TimeSpan.TicksPerDay), dt.Kind); #endregion Round DateTime @@ -138,9 +153,7 @@ namespace System /// The time value to round. /// public static TimeSpan RoundToSecond(this TimeSpan timeSpan) - { - return new TimeSpan(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerSecond)); - } + => new(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerSecond)); /// /// Rounds the to full minutes. @@ -148,9 +161,7 @@ namespace System /// The time value to round. /// public static TimeSpan RoundToMinute(this TimeSpan timeSpan) - { - return new TimeSpan(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerMinute)); - } + => new(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerMinute)); /// /// Rounds the to full hours. @@ -158,9 +169,7 @@ namespace System /// The time value to round. /// public static TimeSpan RoundToHour(this TimeSpan timeSpan) - { - return new TimeSpan(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerHour)); - } + => new(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerHour)); /// /// Rounds the to full days. @@ -168,15 +177,11 @@ namespace System /// The time value to round. /// public static TimeSpan RoundToDay(this TimeSpan timeSpan) - { - return new TimeSpan(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerDay)); - } + => new(RoundTicks(timeSpan.Ticks, TimeSpan.TicksPerDay)); #endregion Round TimeSpan private static long RoundTicks(long ticks, long value) - { - return (ticks + value / 2) / value * value; - } + => (ticks + value / 2) / value * value; } } diff --git a/Common.sln b/Common.sln index 24ea6f4..3a5745a 100644 --- a/Common.sln +++ b/Common.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31729.503 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AMWD.Common", "AMWD.Common\AMWD.Common.csproj", "{F512C474-B670-4E47-911E-7C0674AA8E7E}" EndProject @@ -20,6 +20,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AMWD.Common.Tests", "AMWD.Common.Tests\AMWD.Common.Tests.csproj", "{086E3C11-454A-4C8F-AEAA-215BAE9C443F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F2C7556A-99EB-43EB-8954-56A24AFE928F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E5DF156A-6C8B-4004-BA4C-A8DDE6FD3ECD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -38,10 +44,20 @@ Global {7091CECF-C981-4FB9-9CC6-91C4E65A6356}.Debug|Any CPU.Build.0 = Debug|Any CPU {7091CECF-C981-4FB9-9CC6-91C4E65A6356}.Release|Any CPU.ActiveCfg = Release|Any CPU {7091CECF-C981-4FB9-9CC6-91C4E65A6356}.Release|Any CPU.Build.0 = Release|Any CPU + {086E3C11-454A-4C8F-AEAA-215BAE9C443F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {086E3C11-454A-4C8F-AEAA-215BAE9C443F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {086E3C11-454A-4C8F-AEAA-215BAE9C443F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {086E3C11-454A-4C8F-AEAA-215BAE9C443F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {F512C474-B670-4E47-911E-7C0674AA8E7E} = {F2C7556A-99EB-43EB-8954-56A24AFE928F} + {725F40C9-8172-487F-B3D0-D7E38B4DB197} = {F2C7556A-99EB-43EB-8954-56A24AFE928F} + {7091CECF-C981-4FB9-9CC6-91C4E65A6356} = {F2C7556A-99EB-43EB-8954-56A24AFE928F} + {086E3C11-454A-4C8F-AEAA-215BAE9C443F} = {E5DF156A-6C8B-4004-BA4C-A8DDE6FD3ECD} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {961E8DF8-DDF5-4D10-A510-CE409E9962AC} EndGlobalSection