diff --git a/src/Skybrud.Essentials/Time/TimeUtils.DateTime.cs b/src/Skybrud.Essentials/Time/TimeUtils.DateTime.cs index afa942a..97f12ac 100644 --- a/src/Skybrud.Essentials/Time/TimeUtils.DateTime.cs +++ b/src/Skybrud.Essentials/Time/TimeUtils.DateTime.cs @@ -118,6 +118,37 @@ public static DateTime GetEndOfMonth(DateTime time) { #endregion + #region Get ... of quarter + + /// + /// Returns the quarter of the specified . + /// + /// An instance of representing the timestamp. + /// An representing the quarter. + public static int GetQuarter(DateTime timestamp) { + return (int) Math.Ceiling(timestamp.Month / 3d); + } + + /// + /// Returns a new representing the start of the quarter of the specified . + /// + /// The timestamp. + /// An instance of representing the start of the quarter. + public static DateTime GetStartOfQuarter(DateTime timestamp) { + return GetStartOfQuarter(timestamp.Year, GetQuarter(timestamp)).DateTime; + } + + /// + /// Returns a new representing the quarter of the specified . + /// + /// The timestamp. + /// An instance of representing the start of the quarter. + public static DateTime GetEndOfQuarter(DateTime timestamp) { + return GetEndOfQuarter(timestamp.Year, GetQuarter(timestamp)).DateTime; + } + + #endregion + #region Is... /// diff --git a/src/Skybrud.Essentials/Time/TimeUtils.DateTimeOffset.cs b/src/Skybrud.Essentials/Time/TimeUtils.DateTimeOffset.cs index ebbfd7b..d42bc1e 100644 --- a/src/Skybrud.Essentials/Time/TimeUtils.DateTimeOffset.cs +++ b/src/Skybrud.Essentials/Time/TimeUtils.DateTimeOffset.cs @@ -183,6 +183,84 @@ public static DateTimeOffset GetEndOfMonth(DateTimeOffset time, TimeZoneInfo? ti #endregion + #region Get ... of quarter + + /// + /// Returns the quarter of the specified . + /// + /// An instance of representing the timestamp. + /// An representing the quarter. + public static int GetQuarter(DateTimeOffset timestamp) { + return (int) Math.Ceiling(timestamp.Month / 3d); + } + + /// + /// Returns a new representing the start of the quarter of the specified . + /// + /// The timestamp. + /// An instance of representing the start of the quarter. + public static DateTimeOffset GetStartOfQuarter(DateTimeOffset timestamp) { + return new DateTimeOffset(timestamp.Year, 3 * GetQuarter(timestamp) - 2, 1, 0, 0, 0, timestamp.Offset); + } + + /// + /// Returns a new representing the start of the quarter of the specified . + /// + /// The timestamp. + /// The time zone for which the reuslt should be adjusted. + /// An instance of representing the start of the quarter. + public static DateTimeOffset GetStartOfQuarter(DateTimeOffset timestamp, TimeZoneInfo? timeZone) { + + // Get the start of the quarter + var start = GetStartOfQuarter(timestamp); + + // Adjust to the specified time zone + start = timeZone == null ? start : TimeZoneInfo.ConvertTime(start, timeZone); + + // Adjust for dayligt savings + if (start.Hour == 23) start = start.AddHours(+1); + if (start.Hour == 01) start = start.AddHours(-1); + + return start; + + } + + /// + /// Returns a new representing the end of the quarter of the specified . + /// + /// The timestamp. + /// An instance of representing the end of the quarter. + public static DateTimeOffset GetEndOfQuarter(DateTimeOffset timestamp) { + return GetEndOfQuarter(timestamp.Year, GetQuarter(timestamp)); + } + + /// + /// Returns a new representing the end of the quarter of the specified . + /// + /// The timestamp. + /// The time zone for which the reuslt should be adjusted. + /// An instance of representing the end of the quarter. + public static DateTimeOffset GetEndOfQuarter(DateTimeOffset timestamp, TimeZoneInfo? timeZone) { + + // Get the end of the quarter + var end = GetEndOfQuarter(timestamp); + + // Adjust to the specified time zone + end = timeZone == null ? end : TimeZoneInfo.ConvertTime(end, timeZone); + + // Adjust for dayligt savings + switch (end.Hour) { + case 22: end = end.AddHours(+1); break; + case 00: end = end.AddHours(-1); break; + case 01: end = end.AddHours(-2); break; + } + + return end; + + } + + #endregion + #region Is... /// diff --git a/src/Skybrud.Essentials/Time/TimeUtils.Quarters.cs b/src/Skybrud.Essentials/Time/TimeUtils.Quarters.cs index f4dfa5c..a0c2388 100644 --- a/src/Skybrud.Essentials/Time/TimeUtils.Quarters.cs +++ b/src/Skybrud.Essentials/Time/TimeUtils.Quarters.cs @@ -6,22 +6,53 @@ namespace Skybrud.Essentials.Time { public static partial class TimeUtils { - /// - /// Returns the quarter of the specified . - /// - /// An instance of representing the timestamp. - /// An representing the quarter. - public static int GetQuarter(DateTime timestamp) { - return (int) Math.Ceiling(timestamp.Month / 3d); + internal static int GetStartMonthOfQuarter(int quarter) { + return 3 * quarter - 2; + } + + internal static int GetStartMonthOfQuarter(DateTime date) { + return GetStartMonthOfQuarter(GetQuarter(date)); + } + + internal static int GetStartMonthOfQuarter(DateTimeOffset date) { + return GetStartMonthOfQuarter(GetQuarter(date)); + } + + internal static int GetStartMonthOfQuarter(EssentialsDate date) { + return GetStartMonthOfQuarter(GetQuarter(date)); + } + + internal static int GetStartMonthOfQuarter(EssentialsTime date) { + return GetStartMonthOfQuarter(GetQuarter(date)); + } + + internal static int GetEndMonthOfQuarter(int quarter) { + return 3 * quarter + 1; + } + + internal static int GetEndMonthOfQuarter(DateTime date) { + return GetEndMonthOfQuarter(GetQuarter(date)); + } + + internal static int GetEndMonthOfQuarter(DateTimeOffset date) { + return GetEndMonthOfQuarter(GetQuarter(date)); + } + + internal static int GetEndMonthOfQuarter(EssentialsDate date) { + return GetEndMonthOfQuarter(GetQuarter(date)); + } + + internal static int GetEndMonthOfQuarter(EssentialsTime date) { + return GetEndMonthOfQuarter(GetQuarter(date)); } /// - /// Returns the quarter of the specified . + /// Returns the quarter of the specified . /// - /// An instance of representing the timestamp. + /// An instance of representing the date. /// An representing the quarter. - public static int GetQuarter(DateTimeOffset timestamp) { - return (int) Math.Ceiling(timestamp.Month / 3d); + public static int GetQuarter(EssentialsDate date) { + return (int) Math.Ceiling(date.Month / 3d); } /// @@ -54,46 +85,6 @@ public static DateTimeOffset GetStartOfQuarter(int year, int quarter, TimeSpan o return new DateTimeOffset(year, 3 * quarter - 2, 1, 0, 0, 0, offset); } - /// - /// Returns a new representing the start of the quarter of the specified . - /// - /// The timestamp. - /// An instance of representing the start of the quarter. - public static DateTime GetStartOfQuarter(DateTime timestamp) { - return GetStartOfQuarter(timestamp.Year, GetQuarter(timestamp)).DateTime; - } - - /// - /// Returns a new representing the start of the quarter of the specified . - /// - /// The timestamp. - /// An instance of representing the start of the quarter. - public static DateTimeOffset GetStartOfQuarter(DateTimeOffset timestamp) { - return new DateTimeOffset(timestamp.Year, 3 * GetQuarter(timestamp) - 2, 1, 0, 0, 0, timestamp.Offset); - } - - /// - /// Returns a new representing the start of the quarter of the specified . - /// - /// The timestamp. - /// The time zone for which the reuslt should be adjusted. - /// An instance of representing the start of the quarter. - public static DateTimeOffset GetStartOfQuarter(DateTimeOffset timestamp, TimeZoneInfo? timeZone) { - - // Get the start of the quarter - var start = GetStartOfQuarter(timestamp); - - // Adjust to the specified time zone - start = timeZone == null ? start : TimeZoneInfo.ConvertTime(start, timeZone); - - // Adjust for dayligt savings - if (start.Hour == 23) start = start.AddHours(+1); - if (start.Hour == 01) start = start.AddHours(-1); - - return start; - - } - /// /// Returns a new representing the start of the quarter of the specified . /// @@ -133,49 +124,6 @@ public static DateTimeOffset GetEndOfQuarter(int year, int quarter, TimeSpan off } - /// - /// Returns a new representing the quarter of the specified . - /// - /// The timestamp. - /// An instance of representing the start of the quarter. - public static DateTime GetEndOfQuarter(DateTime timestamp) { - return GetEndOfQuarter(timestamp.Year, GetQuarter(timestamp)).DateTime; - } - - /// - /// Returns a new representing the end of the quarter of the specified . - /// - /// The timestamp. - /// An instance of representing the end of the quarter. - public static DateTimeOffset GetEndOfQuarter(DateTimeOffset timestamp) { - return GetEndOfQuarter(timestamp.Year, GetQuarter(timestamp)); - } - - /// - /// Returns a new representing the end of the quarter of the specified . - /// - /// The timestamp. - /// The time zone for which the reuslt should be adjusted. - /// An instance of representing the end of the quarter. - public static DateTimeOffset GetEndOfQuarter(DateTimeOffset timestamp, TimeZoneInfo? timeZone) { - - // Get the end of the quarter - var end = GetEndOfQuarter(timestamp); - - // Adjust to the specified time zone - end = timeZone == null ? end : TimeZoneInfo.ConvertTime(end, timeZone); - - // Adjust for dayligt savings - switch (end.Hour) { - case 22: end = end.AddHours(+1); break; - case 00: end = end.AddHours(-1); break; - case 01: end = end.AddHours(-2); break; - } - - return end; - - } - /// /// Returns a new representing the end of the quarter of the specified . /// diff --git a/src/UnitTestProject1/Time/DateTimeOffsetTests.cs b/src/UnitTestProject1/Time/Time/DateTimeOffsetTests.cs similarity index 75% rename from src/UnitTestProject1/Time/DateTimeOffsetTests.cs rename to src/UnitTestProject1/Time/Time/DateTimeOffsetTests.cs index 67726ee..d52c870 100644 --- a/src/UnitTestProject1/Time/DateTimeOffsetTests.cs +++ b/src/UnitTestProject1/Time/Time/DateTimeOffsetTests.cs @@ -3,7 +3,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Skybrud.Essentials.Time; -namespace UnitTestProject1.Time { +namespace UnitTestProject1.Time.Time { [TestClass] public class DateTimeOffsetTests { @@ -118,7 +118,7 @@ public void GetEndOfDay() { Assert.AreEqual(s.Expected, result2.ToString(Format), $"Sample at index {i} failed test (EssentialsTime)"); - Assert.AreEqual(s.Expected, result2.ToString(Format), $"Sample at index {i} failed test (EssentialsTime)"); + Assert.AreEqual(s.Expected, result3.ToString(Format), $"Sample at index {i} failed test (EssentialsTime)"); } @@ -352,6 +352,120 @@ public void GetEndOfMonth() { } + [TestMethod] + public void GetStartOfQuarter() { + + TimeZoneInfo utc = TimeZoneInfo.FindSystemTimeZoneById("UTC"); + TimeZoneInfo romance = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time"); + + var samples = new[] { + + new GetOfDaySample("2019-01-01 00:00:00:000 +00:00", "2019-03-18 12:00:00:000 +00:00", null), + new GetOfDaySample("2019-01-01 00:00:00:000 +00:00", "2019-03-23 12:00:00:000 +00:00", null), + new GetOfDaySample("2019-01-01 00:00:00:000 +00:00", "2019-03-26 12:00:00:000 +00:00", null), + + new GetOfDaySample("2019-01-01 00:00:00:000 +00:00", "2019-03-18 12:00:00:000 +00:00", utc), + new GetOfDaySample("2019-01-01 00:00:00:000 +00:00", "2019-03-23 12:00:00:000 +00:00", utc), + new GetOfDaySample("2019-01-01 00:00:00:000 +00:00", "2019-03-26 12:00:00:000 +00:00", utc), + + new GetOfDaySample("2019-01-01 00:00:00:000 +01:00", "2019-03-23 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-01-01 00:00:00:000 +01:00", "2019-03-24 12:00:00:000 +01:00", romance), + + new GetOfDaySample("2019-01-01 00:00:00:000 +01:00", "2019-03-25 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-01-01 00:00:00:000 +01:00", "2019-03-26 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-01-01 00:00:00:000 +01:00", "2019-03-27 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-01-01 00:00:00:000 +01:00", "2019-03-28 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-01-01 00:00:00:000 +01:00", "2019-03-29 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-01-01 00:00:00:000 +01:00", "2019-03-30 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-01-01 00:00:00:000 +01:00", "2019-03-31 12:00:00:000 +02:00", romance), + + new GetOfDaySample("2019-04-01 00:00:00:000 +02:00", "2019-04-01 12:00:00:000 +02:00", romance), + new GetOfDaySample("2019-04-01 00:00:00:000 +02:00", "2019-04-02 12:00:00:000 +02:00", romance), + + new GetOfDaySample("2019-10-01 00:00:00:000 +02:00", "2019-10-23 12:00:00:000 +02:00", romance), + new GetOfDaySample("2019-10-01 00:00:00:000 +02:00", "2019-10-25 12:00:00:000 +02:00", romance), + new GetOfDaySample("2019-10-01 00:00:00:000 +02:00", "2019-10-27 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-10-01 00:00:00:000 +02:00", "2019-10-29 12:00:00:000 +01:00", romance) + + }; + + for (int i = 0; i < samples.Length; i++) { + + var s = samples[i]; + + DateTimeOffset result1 = TimeUtils.GetStartOfQuarter(s.Time, s.TimeZone); + + EssentialsTime result2 = new EssentialsTime(s.Time, s.TimeZone).GetStartOfQuarter(); + + EssentialsTime result3 = new EssentialsTime(s.Time, s.TimeZone).GetStartOfQuarter(s.TimeZone); + + Assert.AreEqual(s.Expected, result1.ToString(Format), $"Sample at index {i} failed test (DateTimeOffset)"); + + Assert.AreEqual(s.Expected, result2.ToString(Format), $"Sample at index {i} failed test (EssentialsTime)"); + + Assert.AreEqual(s.Expected, result3.ToString(Format), $"Sample at index {i} failed test (EssentialsTime)"); + + } + + } + + [TestMethod] + public void GetEndOfQuarter() { + + TimeZoneInfo utc = TimeZoneInfo.FindSystemTimeZoneById("UTC"); + TimeZoneInfo romance = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time"); + + var samples = new[] { + + new GetOfDaySample("2019-03-31 23:59:59:999 +00:00", "2019-03-18 12:00:00:000 +00:00", null), + new GetOfDaySample("2019-03-31 23:59:59:999 +00:00", "2019-03-23 12:00:00:000 +00:00", null), + new GetOfDaySample("2019-03-31 23:59:59:999 +00:00", "2019-03-26 12:00:00:000 +00:00", null), + + new GetOfDaySample("2019-03-31 23:59:59:999 +00:00", "2019-03-18 12:00:00:000 +00:00", utc), + new GetOfDaySample("2019-03-31 23:59:59:999 +00:00", "2019-03-23 12:00:00:000 +00:00", utc), + new GetOfDaySample("2019-03-31 23:59:59:999 +00:00", "2019-03-26 12:00:00:000 +00:00", utc), + + new GetOfDaySample("2019-03-31 23:59:59:999 +02:00", "2019-03-23 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-03-31 23:59:59:999 +02:00", "2019-03-24 12:00:00:000 +01:00", romance), + + new GetOfDaySample("2019-03-31 23:59:59:999 +02:00", "2019-03-25 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-03-31 23:59:59:999 +02:00", "2019-03-26 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-03-31 23:59:59:999 +02:00", "2019-03-27 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-03-31 23:59:59:999 +02:00", "2019-03-28 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-03-31 23:59:59:999 +02:00", "2019-03-29 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-03-31 23:59:59:999 +02:00", "2019-03-30 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-03-31 23:59:59:999 +02:00", "2019-03-31 12:00:00:000 +02:00", romance), + + new GetOfDaySample("2019-06-30 23:59:59:999 +02:00", "2019-04-01 12:00:00:000 +02:00", romance), + new GetOfDaySample("2019-06-30 23:59:59:999 +02:00", "2019-04-02 12:00:00:000 +02:00", romance), + + new GetOfDaySample("2019-12-31 23:59:59:999 +01:00", "2019-10-23 12:00:00:000 +02:00", romance), + new GetOfDaySample("2019-12-31 23:59:59:999 +01:00", "2019-10-25 12:00:00:000 +02:00", romance), + new GetOfDaySample("2019-12-31 23:59:59:999 +01:00", "2019-10-27 12:00:00:000 +01:00", romance), + new GetOfDaySample("2019-12-31 23:59:59:999 +01:00", "2019-10-29 12:00:00:000 +01:00", romance) + + }; + + for (int i = 0; i < samples.Length; i++) { + + var s = samples[i]; + + DateTimeOffset result1 = TimeUtils.GetEndOfQuarter(s.Time, s.TimeZone); + + EssentialsTime result2 = new EssentialsTime(s.Time, s.TimeZone).GetEndOfQuarter(); + + EssentialsTime result3 = new EssentialsTime(s.Time, s.TimeZone).GetEndOfQuarter(s.TimeZone); + + Assert.AreEqual(s.Expected, result1.ToString(Format), $"Sample at index {i} failed test (DateTimeOffset)"); + + Assert.AreEqual(s.Expected, result2.ToString(Format), $"Sample at index {i} failed test (EssentialsTime)"); + + Assert.AreEqual(s.Expected, result3.ToString(Format), $"Sample at index {i} failed test (EssentialsTime)"); + + } + + } + public class GetOfDaySample { diff --git a/src/UnitTestProject1/Time/Time/DateTimeTests.cs b/src/UnitTestProject1/Time/Time/DateTimeTests.cs index 00ee0c7..dadc846 100644 --- a/src/UnitTestProject1/Time/Time/DateTimeTests.cs +++ b/src/UnitTestProject1/Time/Time/DateTimeTests.cs @@ -62,6 +62,67 @@ public void GetEndOfWeek() { } + [TestMethod] + public void GetStartOfMonth() { + + DateTime time = new DateTime(2023, 1, 22, 12, 0, 0); + + DateTime result = TimeUtils.GetStartOfMonth(time); + + Assert.AreEqual("2023-01-01 00:00:00", result.ToString(_format, CultureInfo.CurrentCulture)); + + } + + [TestMethod] + public void GetEndOfMonth() { + + DateTime time = new DateTime(2023, 1, 22, 12, 0, 0); + + var result1 = TimeUtils.GetEndOfMonth(time); + + Assert.AreEqual("2023-01-31 23:59:59", result1.ToString(_format, CultureInfo.CurrentCulture)); + + } + + [TestMethod] + public void GetQuarter() { + + DateTime time1 = new DateTime(2023, 1, 22, 12, 0, 0); + DateTime time2 = new DateTime(2023, 6, 5, 12, 0, 0); + DateTime time3 = new DateTime(2023, 7, 4, 12, 0, 0); + + int result1 = TimeUtils.GetQuarter(time1); + int result2 = TimeUtils.GetQuarter(time2); + int result3 = TimeUtils.GetQuarter(time3); + + Assert.AreEqual(1, result1); + Assert.AreEqual(2, result2); + Assert.AreEqual(3, result3); + + } + + [TestMethod] + public void GetStartOfQuarter() { + + DateTime time = new DateTime(2023, 1, 22, 12, 0, 0); + + DateTime result = TimeUtils.GetStartOfQuarter(time); + + Assert.AreEqual("2023-01-01 00:00:00", result.ToString(_format, CultureInfo.CurrentCulture)); + + } + + [TestMethod] + public void GetEndOfQuarter() { + + DateTime time = new DateTime(2023, 1, 22, 12, 0, 0); + + var result1 = TimeUtils.GetEndOfQuarter(time); + + Assert.AreEqual("2023-03-31 23:59:59", result1.ToString(_format, CultureInfo.CurrentCulture)); + + } + } } \ No newline at end of file diff --git a/src/UnitTestProject1/UnitTestProject1.csproj b/src/UnitTestProject1/UnitTestProject1.csproj index 7fc739c..f953934 100644 --- a/src/UnitTestProject1/UnitTestProject1.csproj +++ b/src/UnitTestProject1/UnitTestProject1.csproj @@ -110,7 +110,7 @@ - +