diff --git a/specs/Qowaiv.Specs/Clock_specs.cs b/specs/Qowaiv.Specs/Clock_specs.cs index e93e3297..c4321c27 100644 --- a/specs/Qowaiv.Specs/Clock_specs.cs +++ b/specs/Qowaiv.Specs/Clock_specs.cs @@ -17,17 +17,17 @@ public void Now_equals_UTC_now_with_the_time_zone_offset() { using (Clock.SetTimeAndTimeZoneForCurrentContext(() => Svo.DateTime, TestTimeZones.EastAustraliaStandardTime)) { - Clock.Now().Should().Be(new LocalDateTime(2017, 06, 11, 16, 15, 00)); + Clock.Now().Should().Be(new DateTimeOffset(2017, 06, 11, 16, 15, 00, TimeSpan.FromHours(+10))); } } [Test] - public void NowWithOffset_equals_UTC_now_with_the_time_zone_offset() + public void Now_for_time_zone_equals_UTC_now_with_the_time_zone_offset() { - using (Clock.SetTimeAndTimeZoneForCurrentContext(() => Svo.DateTime, Svo.TimeZone)) + using (Clock.SetTimeAndTimeZoneForCurrentContext(() => Svo.DateTime, TestTimeZones.EastAustraliaStandardTime)) { - var date_time_offset = new DateTimeOffset(new DateTime(2017, 06, 11, 16, 15, 0, DateTimeKind.Unspecified), TimeSpan.FromHours(+10)); - Clock.NowWithOffset().Should().Be(date_time_offset); + var now = Clock.Now(TestTimeZones.LeidenTime); + now.Should().Be(new DateTimeOffset(2017, 06, 11, 06, 48, 00, TimeSpan.FromMinutes(+33))); } } } diff --git a/specs/Qowaiv.Specs/Date_time_offset_specs.cs b/specs/Qowaiv.Specs/Date_time_offset_specs.cs new file mode 100644 index 00000000..1d2a6600 --- /dev/null +++ b/specs/Qowaiv.Specs/Date_time_offset_specs.cs @@ -0,0 +1,78 @@ +using FluentAssertions.Extensions; + +namespace Date_time_offset_specs; + +public class Can_be_adjusted_with +{ + [Test] + public void Date_span_with_months_first() + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).Add(new DateSpan(2, 20)) + .Should().Be(31.August(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2))); + + [Test] + public void Date_span_with_days_first() + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).Add(new DateSpan(2, 20), DateSpanSettings.DaysFirst) + .Should().Be(01.September(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2))); + + [Test] + public void Month_span() + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).Add(MonthSpan.FromMonths(3)) + .Should().Be(11.September(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2))); +} + +public class With_local +{ + [Test] + public void represents_a_local_date_time() + { + 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).ToLocal() + .Should().Be(new LocalDateTime(2017, 06, 11, 06, 15)); + } +} + +public class Can_not_be_adjusted_with +{ + [TestCase(DateSpanSettings.WithoutMonths)] + [TestCase(DateSpanSettings.DaysFirst | DateSpanSettings.MixedSigns)] + public void Date_span_with(DateSpanSettings settings) + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).Invoking(d => d.Add(new DateSpan(2, 20), settings)) + .Should().Throw().WithMessage("Adding a date span only supports 'Default' and 'DaysFirst'.*"); +} + +public class Can_be_related_to +{ + [Test] + public void matching_month() + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).IsIn(Month.June).Should().BeTrue(); + + [Test] + public void none_matching_month() + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).IsIn(Month.February).Should().BeFalse(); + + [Test] + public void matching_year() + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).IsIn(2017.CE()).Should().BeTrue(); + + [Test] + public void none_matching_year() + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).IsIn(2018.CE()).Should().BeFalse(); +} + +public class Can_not_be_related_to +{ + [Test] + public void month_empty() + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).IsIn(Month.Empty).Should().BeFalse(); + + [Test] + public void month_unknown() + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).IsIn(Month.Unknown).Should().BeFalse(); + + [Test] + public void year_empty() + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).IsIn(Year.Empty).Should().BeFalse(); + + [Test] + public void year_unknown() + => 11.June(2017).At(06, 15).WithOffset(TimeSpan.FromHours(+2)).IsIn(Year.Unknown).Should().BeFalse(); +} diff --git a/src/Qowaiv/Clock.cs b/src/Qowaiv/Clock.cs index 66adde58..9ff3a3c3 100644 --- a/src/Qowaiv/Clock.cs +++ b/src/Qowaiv/Clock.cs @@ -17,7 +17,7 @@ namespace Qowaiv; /// [Test] /// public void TestSomething() /// { -/// using(Clock.SetTimeForCurrentContext(() => new DateTime(2017, 06, 11, 00, 00, 000, DateTimeKind.Local)) +/// using(Clock.SetTimeForCurrentContext(() => new DateTimeOffset(2017, 06, 11, 00, 00, 000, TimeSpan.FromHours(+1)) /// { /// // test code. /// } @@ -47,27 +47,16 @@ public static DateTime UtcNow() /// Gets the time zone of the . public static TimeZoneInfo TimeZone => localContextTimeZone.Value ?? globalTimeZone; - /// Gets the current . - [Pure] - public static LocalDateTime Now() => Now(TimeZone); - - /// Gets the current for the specified time zone. - /// - /// The specified time zone. - /// - [Pure] - public static LocalDateTime Now(TimeZoneInfo timeZone) => TimeZoneInfo.ConvertTimeFromUtc(UtcNow(), Guard.NotNull(timeZone)); - /// Gets the current . [Pure] - public static DateTimeOffset NowWithOffset() => NowWithOffset(TimeZone); + public static DateTimeOffset Now() => Now(TimeZone); /// Gets the current for the specified time zone. /// /// The specified time zone. /// [Pure] - public static DateTimeOffset NowWithOffset(TimeZoneInfo timeZone) + public static DateTimeOffset Now(TimeZoneInfo timeZone) { Guard.NotNull(timeZone); var utcNow = UtcNow(); diff --git a/src/Qowaiv/Extensions/System.DateTime.cs b/src/Qowaiv/Extensions/System.DateTime.cs index 9ea4b77b..354af8e1 100644 --- a/src/Qowaiv/Extensions/System.DateTime.cs +++ b/src/Qowaiv/Extensions/System.DateTime.cs @@ -78,7 +78,7 @@ public static class QowaivDateTimeExtensions /// Returns true if the date is in the specified month, otherwise false. /// - /// The date to check. + /// The date time to check. /// /// /// The the date should be in. diff --git a/src/Qowaiv/Extensions/System.DateTimeOffset.cs b/src/Qowaiv/Extensions/System.DateTimeOffset.cs new file mode 100644 index 00000000..b57350aa --- /dev/null +++ b/src/Qowaiv/Extensions/System.DateTimeOffset.cs @@ -0,0 +1,106 @@ +using Qowaiv; + +namespace System; + +/// Extensions on . +public static class QowaivDateTimeOffsetExtensions +{ + /// Returns a new date time offset that adds the value of the specified + /// to the value of this instance. + /// + /// + /// The date time offset to add a to. + /// + /// + /// A object that represents a positive or negative time interval. + /// + /// + /// A new date whose value is the sum of the date and time represented + /// by this instance and the time interval represented by value. + /// + /// + /// The resulting date is less than or greater + /// than . + /// + [Pure] + public static DateTimeOffset Add(this DateTimeOffset d, DateSpan value) => d.Add(value, DateSpanSettings.Default); + + /// Returns a new date time that adds the value of the specified + /// to the value of this instance. + /// + /// + /// The date time to offset add a to. + /// + /// + /// A object that represents a positive or negative time interval. + /// + /// + /// If days are added first, if days are added second. + /// + /// + /// A new date whose value is the sum of the date represented + /// by this instance and the time interval represented by value. + /// + /// + /// The resulting date is less than or greater + /// than . + /// + /// + /// The provided settings have different value then or . + /// + [Pure] + public static DateTimeOffset Add(this DateTimeOffset d, DateSpan value, DateSpanSettings settings) => settings switch + { + DateSpanSettings.DaysFirst => d.AddDays(value.Days).AddMonths(value.TotalMonths), + DateSpanSettings.Default => d.AddMonths(value.TotalMonths).AddDays(value.Days), + _ => throw new ArgumentOutOfRangeException(nameof(settings), QowaivMessages.ArgumentOutOfRangeException_AddDateSpan), + }; + + /// Returns a new date time that adds the value of the specified + /// to the value of this instance. + /// + /// + /// The date time offset to add a to. + /// + /// + /// A object that represents a positive or negative time interval. + /// + /// + /// A new date whose value is the sum of the date and time represented + /// by this instance and the time interval represented by value. + /// + /// + /// The resulting date is less than or greater + /// than . + /// + [Pure] + public static DateTimeOffset Add(this DateTimeOffset d, MonthSpan value) => d.AddMonths(value.TotalMonths); + + /// Returns true if the date is in the specified month, otherwise false. + /// + /// The date time offset to check. + /// + /// + /// The the date should be in. + /// + [Pure] + public static bool IsIn(this DateTimeOffset d, Month month) => !month.IsEmptyOrUnknown() && d.Month == (int)month; + + /// Returns true if the date is in the specified year, otherwise false. + /// + /// The date time offset to check. + /// + /// + /// The the date should be in. + /// + [Pure] + public static bool IsIn(this DateTimeOffset d, Year year) => !year.IsEmptyOrUnknown() && d.Year == (int)year; + + /// Returns the representation of the date time offset. + /// + /// The date time offset. + /// + [Pure] + public static LocalDateTime ToLocal(this DateTimeOffset d) + => new(d.LocalDateTime.Ticks); +} diff --git a/src/Qowaiv/Qowaiv.csproj b/src/Qowaiv/Qowaiv.csproj index 3bcef199..83a4ef6c 100644 --- a/src/Qowaiv/Qowaiv.csproj +++ b/src/Qowaiv/Qowaiv.csproj @@ -9,6 +9,9 @@ Qowaiv v7.0.0 +- Clock.Now returns DateTimeOffset. (breaking) +- Clock.NowWithOffset is dropped. (breaking) +- Extension methods on DateTimeOffset. - Implement INumber<Percentage>. #367 - Implement INumber<Amount>. #370 - Introduction of the IEmpty<TSelf> interface. #364