From ef9c18668477df823e223c3567d3297a1bc41857 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Thu, 28 Apr 2022 10:27:32 +0100 Subject: [PATCH] Add IsLeapYear for DateTime(Offset) and numeric types --- X10D.Tests/src/Time/ByteTests.cs | 29 +++++++++++++++++ X10D.Tests/src/Time/DateTimeOffsetTests.cs | 28 +++++++++++++++++ X10D.Tests/src/Time/DateTimeTests.cs | 28 +++++++++++++++++ X10D.Tests/src/Time/Int16Tests.cs | 36 +++++++++++++++++++++- X10D.Tests/src/Time/Int32Tests.cs | 34 ++++++++++++++++++++ X10D.Tests/src/Time/Int64Tests.cs | 34 ++++++++++++++++++++ X10D.Tests/src/Time/SByteTests.cs | 29 +++++++++++++++++ X10D.Tests/src/Time/UInt16Tests.cs | 30 ++++++++++++++++++ X10D.Tests/src/Time/UInt32Tests.cs | 30 ++++++++++++++++++ X10D.Tests/src/Time/UInt64Tests.cs | 30 ++++++++++++++++++ X10D/src/ExceptionMessages.Designer.cs | 9 ++++++ X10D/src/ExceptionMessages.resx | 3 ++ X10D/src/Time/ByteExtensions.cs | 25 ++++++++++++++- X10D/src/Time/DateTimeExtensions.cs | 13 ++++++++ X10D/src/Time/DateTimeOffsetExtensions.cs | 13 ++++++++ X10D/src/Time/Int16Extensions.cs | 31 ++++++++++++++++++- X10D/src/Time/Int32Extensions.cs | 31 ++++++++++++++++++- X10D/src/Time/Int64Extensions.cs | 31 ++++++++++++++++++- X10D/src/Time/SByteExtensions.cs | 31 ++++++++++++++++++- X10D/src/Time/UInt16Extensions.cs | 25 ++++++++++++++- X10D/src/Time/UInt32Extensions.cs | 25 ++++++++++++++- X10D/src/Time/UInt64Extensions.cs | 25 ++++++++++++++- 22 files changed, 561 insertions(+), 9 deletions(-) diff --git a/X10D.Tests/src/Time/ByteTests.cs b/X10D.Tests/src/Time/ByteTests.cs index 602db04..705a149 100644 --- a/X10D.Tests/src/Time/ByteTests.cs +++ b/X10D.Tests/src/Time/ByteTests.cs @@ -18,6 +18,35 @@ public class ByteTests Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), ((byte)0).FromUnixTimeSeconds()); } + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenMultipleOf100() + { + Assert.IsFalse(((byte)100).IsLeapYear()); + Assert.IsFalse(((byte)200).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenOddNumber() + { + Assert.IsFalse(((byte)1).IsLeapYear()); + Assert.IsFalse(((byte)101).IsLeapYear()); + Assert.IsFalse(((byte)201).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeTrue_GivenMultipleOf4() + { + Assert.IsTrue(((byte)4).IsLeapYear()); + Assert.IsTrue(((byte)104).IsLeapYear()); + Assert.IsTrue(((byte)204).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldThrow_GivenZero() + { + Assert.ThrowsException(() => ((byte)0).IsLeapYear()); + } + [TestMethod] public void TicksMillisecondsSecondsMinutesDaysHoursWeeks_ShouldBePositive_GivenOne() { diff --git a/X10D.Tests/src/Time/DateTimeOffsetTests.cs b/X10D.Tests/src/Time/DateTimeOffsetTests.cs index eb9f1cc..4deba4b 100644 --- a/X10D.Tests/src/Time/DateTimeOffsetTests.cs +++ b/X10D.Tests/src/Time/DateTimeOffsetTests.cs @@ -37,6 +37,34 @@ public class DateTimeOffsetTests Assert.AreEqual(new DateTime(today.Year, today.Month, 1), today.FirstDayOfMonth()); } + [TestMethod] + public void IsLeapYear_ShouldBeFalse_Given1999() + { + DateTimeOffset date = new DateTime(1999, 1, 1); + Assert.IsFalse(date.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeTrue_Given2000() + { + DateTimeOffset date = new DateTime(2000, 1, 1); + Assert.IsTrue(date.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_Given2001() + { + DateTimeOffset date = new DateTime(2001, 1, 1); + Assert.IsFalse(date.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_Given2100() + { + DateTimeOffset date = new DateTime(2100, 1, 1); + Assert.IsFalse(date.IsLeapYear()); + } + [TestMethod] public void LastSaturday_ShouldBe29th_Given1Jan2000() { diff --git a/X10D.Tests/src/Time/DateTimeTests.cs b/X10D.Tests/src/Time/DateTimeTests.cs index 0ea064a..b6c3174 100644 --- a/X10D.Tests/src/Time/DateTimeTests.cs +++ b/X10D.Tests/src/Time/DateTimeTests.cs @@ -37,6 +37,34 @@ public class DateTimeTests Assert.AreEqual(new DateTime(today.Year, today.Month, 1), today.FirstDayOfMonth()); } + [TestMethod] + public void IsLeapYear_ShouldBeFalse_Given1999() + { + var date = new DateTime(1999, 1, 1); + Assert.IsFalse(date.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeTrue_Given2000() + { + var date = new DateTime(2000, 1, 1); + Assert.IsTrue(date.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_Given2001() + { + var date = new DateTime(2001, 1, 1); + Assert.IsFalse(date.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_Given2100() + { + var date = new DateTime(2100, 1, 1); + Assert.IsFalse(date.IsLeapYear()); + } + [TestMethod] public void LastSaturday_ShouldBe29th_Given1Jan2000() { diff --git a/X10D.Tests/src/Time/Int16Tests.cs b/X10D.Tests/src/Time/Int16Tests.cs index 36b2906..f2434fe 100644 --- a/X10D.Tests/src/Time/Int16Tests.cs +++ b/X10D.Tests/src/Time/Int16Tests.cs @@ -11,13 +11,47 @@ public class Int16Tests { Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), ((short)0).FromUnixTimeMilliseconds()); } - + [TestMethod] public void FromUnixTimeSeconds_ShouldBeEpoch_GivenZero() { Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), ((short)0).FromUnixTimeSeconds()); } + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenMultipleOf100() + { + Assert.IsFalse(((short)100).IsLeapYear()); + Assert.IsFalse(((short)-100).IsLeapYear()); + Assert.IsFalse(((short)1900).IsLeapYear()); + Assert.IsFalse(((short)2100).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenOddNumber() + { + Assert.IsFalse(((short)1).IsLeapYear()); + Assert.IsFalse(((short)101).IsLeapYear()); + Assert.IsFalse(((short)-101).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeTrue_GivenMultipleOf4Or400() + { + Assert.IsTrue(((short)-401).IsLeapYear()); + Assert.IsTrue(((short)-105).IsLeapYear()); + Assert.IsTrue(((short)4).IsLeapYear()); + Assert.IsTrue(((short)104).IsLeapYear()); + Assert.IsTrue(((short)400).IsLeapYear()); + Assert.IsTrue(((short)2000).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldThrow_GivenZero() + { + Assert.ThrowsException(() => ((short)0).IsLeapYear()); + } + [TestMethod] public void TicksMillisecondsSecondsMinutesDaysHoursWeeks_ShouldBeNegative_GivenMinusOne() { diff --git a/X10D.Tests/src/Time/Int32Tests.cs b/X10D.Tests/src/Time/Int32Tests.cs index d954f8d..7d6670b 100644 --- a/X10D.Tests/src/Time/Int32Tests.cs +++ b/X10D.Tests/src/Time/Int32Tests.cs @@ -18,6 +18,40 @@ public class Int32Tests Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), 0.FromUnixTimeSeconds()); } + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenMultipleOf100() + { + Assert.IsFalse(100.IsLeapYear()); + Assert.IsFalse((-100).IsLeapYear()); + Assert.IsFalse(1900.IsLeapYear()); + Assert.IsFalse(2100.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenOddNumber() + { + Assert.IsFalse(1.IsLeapYear()); + Assert.IsFalse(101.IsLeapYear()); + Assert.IsFalse((-101).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeTrue_GivenMultipleOf4Or400() + { + Assert.IsTrue((-401).IsLeapYear()); + Assert.IsTrue((-105).IsLeapYear()); + Assert.IsTrue(4.IsLeapYear()); + Assert.IsTrue(104.IsLeapYear()); + Assert.IsTrue(400.IsLeapYear()); + Assert.IsTrue(2000.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldThrow_GivenZero() + { + Assert.ThrowsException(() => 0.IsLeapYear()); + } + [TestMethod] public void TicksMillisecondsSecondsMinutesDaysHoursWeeks_ShouldBeNegative_GivenMinusOne() { diff --git a/X10D.Tests/src/Time/Int64Tests.cs b/X10D.Tests/src/Time/Int64Tests.cs index 99525cc..f0459eb 100644 --- a/X10D.Tests/src/Time/Int64Tests.cs +++ b/X10D.Tests/src/Time/Int64Tests.cs @@ -18,6 +18,40 @@ public class Int64Tests Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), 0L.FromUnixTimeSeconds()); } + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenMultipleOf100() + { + Assert.IsFalse(100L.IsLeapYear()); + Assert.IsFalse((-100L).IsLeapYear()); + Assert.IsFalse(1900L.IsLeapYear()); + Assert.IsFalse(2100L.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenOddNumber() + { + Assert.IsFalse(1L.IsLeapYear()); + Assert.IsFalse(101L.IsLeapYear()); + Assert.IsFalse((-101L).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeTrue_GivenMultipleOf4Or400() + { + Assert.IsTrue((-401L).IsLeapYear()); + Assert.IsTrue((-105L).IsLeapYear()); + Assert.IsTrue(4L.IsLeapYear()); + Assert.IsTrue(104L.IsLeapYear()); + Assert.IsTrue(400L.IsLeapYear()); + Assert.IsTrue(2000L.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldThrow_GivenZero() + { + Assert.ThrowsException(() => 0L.IsLeapYear()); + } + [TestMethod] public void TicksMillisecondsSecondsMinutesDaysHoursWeeks_ShouldBeNegative_GivenMinusOne() { diff --git a/X10D.Tests/src/Time/SByteTests.cs b/X10D.Tests/src/Time/SByteTests.cs index dd648b7..8189c6f 100644 --- a/X10D.Tests/src/Time/SByteTests.cs +++ b/X10D.Tests/src/Time/SByteTests.cs @@ -19,6 +19,35 @@ public class SByteTests Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), ((sbyte)0).FromUnixTimeSeconds()); } + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenMultipleOf100() + { + Assert.IsFalse(((sbyte)100).IsLeapYear()); + Assert.IsFalse(((sbyte)-100).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenOddNumber() + { + Assert.IsFalse(((sbyte)1).IsLeapYear()); + Assert.IsFalse(((sbyte)101).IsLeapYear()); + Assert.IsFalse(((sbyte)-101).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeTrue_GivenMultipleOf4() + { + Assert.IsTrue(((sbyte)4).IsLeapYear()); + Assert.IsTrue(((sbyte)104).IsLeapYear()); + Assert.IsTrue(((sbyte)-105).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldThrow_GivenZero() + { + Assert.ThrowsException(() => ((sbyte)0).IsLeapYear()); + } + [TestMethod] public void TicksMillisecondsSecondsMinutesDaysHoursWeeks_ShouldBeZero_GivenZero() { diff --git a/X10D.Tests/src/Time/UInt16Tests.cs b/X10D.Tests/src/Time/UInt16Tests.cs index e9003b3..89390d9 100644 --- a/X10D.Tests/src/Time/UInt16Tests.cs +++ b/X10D.Tests/src/Time/UInt16Tests.cs @@ -7,6 +7,36 @@ namespace X10D.Tests.Time; [CLSCompliant(false)] public class UInt16Tests { + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenMultipleOf100() + { + Assert.IsFalse(((ushort)100).IsLeapYear()); + Assert.IsFalse(((ushort)1900).IsLeapYear()); + Assert.IsFalse(((ushort)2100).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenOddNumber() + { + Assert.IsFalse(((ushort)1).IsLeapYear()); + Assert.IsFalse(((ushort)101).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeTrue_GivenMultipleOf4Or400() + { + Assert.IsTrue(((ushort)4).IsLeapYear()); + Assert.IsTrue(((ushort)104).IsLeapYear()); + Assert.IsTrue(((ushort)400).IsLeapYear()); + Assert.IsTrue(((ushort)2000).IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldThrow_GivenZero() + { + Assert.ThrowsException(() => ((ushort)0).IsLeapYear()); + } + [TestMethod] public void TicksMillisecondsSecondsMinutesDaysHoursWeeks_ShouldBePositive_GivenOne() { diff --git a/X10D.Tests/src/Time/UInt32Tests.cs b/X10D.Tests/src/Time/UInt32Tests.cs index 25698aa..8036cd8 100644 --- a/X10D.Tests/src/Time/UInt32Tests.cs +++ b/X10D.Tests/src/Time/UInt32Tests.cs @@ -7,6 +7,36 @@ namespace X10D.Tests.Time; [CLSCompliant(false)] public class UInt32Tests { + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenMultipleOf100() + { + Assert.IsFalse(100U.IsLeapYear()); + Assert.IsFalse(1900U.IsLeapYear()); + Assert.IsFalse(2100U.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenOddNumber() + { + Assert.IsFalse(1U.IsLeapYear()); + Assert.IsFalse(101U.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeTrue_GivenMultipleOf4Or400() + { + Assert.IsTrue(4U.IsLeapYear()); + Assert.IsTrue(104U.IsLeapYear()); + Assert.IsTrue(400U.IsLeapYear()); + Assert.IsTrue(2000U.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldThrow_GivenZero() + { + Assert.ThrowsException(() => 0U.IsLeapYear()); + } + [TestMethod] public void TicksMillisecondsSecondsMinutesDaysHoursWeeks_ShouldBePositive_GivenOne() { diff --git a/X10D.Tests/src/Time/UInt64Tests.cs b/X10D.Tests/src/Time/UInt64Tests.cs index ebfac8b..26d5ad2 100644 --- a/X10D.Tests/src/Time/UInt64Tests.cs +++ b/X10D.Tests/src/Time/UInt64Tests.cs @@ -7,6 +7,36 @@ namespace X10D.Tests.Time; [CLSCompliant(false)] public class UInt64Tests { + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenMultipleOf100() + { + Assert.IsFalse(100UL.IsLeapYear()); + Assert.IsFalse(1900UL.IsLeapYear()); + Assert.IsFalse(2100UL.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeFalse_GivenOddNumber() + { + Assert.IsFalse(1UL.IsLeapYear()); + Assert.IsFalse(101UL.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldBeTrue_GivenMultipleOf4Or400() + { + Assert.IsTrue(4UL.IsLeapYear()); + Assert.IsTrue(104UL.IsLeapYear()); + Assert.IsTrue(400UL.IsLeapYear()); + Assert.IsTrue(2000UL.IsLeapYear()); + } + + [TestMethod] + public void IsLeapYear_ShouldThrow_GivenZero() + { + Assert.ThrowsException(() => 0UL.IsLeapYear()); + } + [TestMethod] public void TicksMillisecondsSecondsMinutesDaysHoursWeeks_ShouldBePositive_GivenOne() { diff --git a/X10D/src/ExceptionMessages.Designer.cs b/X10D/src/ExceptionMessages.Designer.cs index 6c723af..3f45f18 100644 --- a/X10D/src/ExceptionMessages.Designer.cs +++ b/X10D/src/ExceptionMessages.Designer.cs @@ -185,5 +185,14 @@ namespace X10D { return ResourceManager.GetString("TypeIsNotInterface", resourceCulture); } } + + /// + /// Looks up a localized string similar to Year cannot be zero.. + /// + internal static string YearCannotBeZero { + get { + return ResourceManager.GetString("YearCannotBeZero", resourceCulture); + } + } } } diff --git a/X10D/src/ExceptionMessages.resx b/X10D/src/ExceptionMessages.resx index cba345f..b887f5a 100644 --- a/X10D/src/ExceptionMessages.resx +++ b/X10D/src/ExceptionMessages.resx @@ -65,4 +65,7 @@ count must be greater than or equal to 0. + + Year cannot be zero. + \ No newline at end of file diff --git a/X10D/src/Time/ByteExtensions.cs b/X10D/src/Time/ByteExtensions.cs index 0e097a2..b8e941e 100644 --- a/X10D/src/Time/ByteExtensions.cs +++ b/X10D/src/Time/ByteExtensions.cs @@ -1,10 +1,33 @@ -namespace X10D.Time; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; + +namespace X10D.Time; /// /// Time-related extension methods for . /// public static class ByteExtensions { + /// + /// Returns a value indicating whether the current integer, representing a year, is a leap year. + /// + /// The value whose leap year status to check. + /// + /// if refers to a leap year; otherwise, . + /// + /// is 0. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public static bool IsLeapYear(this byte value) + { + if (value == 0) + { + throw new ArgumentOutOfRangeException(nameof(value), ExceptionMessages.YearCannotBeZero); + } + + return value % 4 == 0 && value % 100 != 0; // mod 400 not required, byte.MaxValue is 255 anyway + } + /// /// Converts a Unix time expressed as the number of milliseconds that have elapsed since 1970-01-01T00:00:00Z to a /// value. diff --git a/X10D/src/Time/DateTimeExtensions.cs b/X10D/src/Time/DateTimeExtensions.cs index 0d99a4f..2b70b7d 100644 --- a/X10D/src/Time/DateTimeExtensions.cs +++ b/X10D/src/Time/DateTimeExtensions.cs @@ -31,6 +31,19 @@ public static class DateTimeExtensions return ((DateTimeOffset)value).FirstDayOfMonth().DateTime; } + /// + /// Returns a value indicating whether the year represented by the current is a leap year. + /// + /// The date whose year to check. + /// + /// if the year represented by is a leap year; otherwise, + /// . + /// + public static bool IsLeapYear(this DateTime value) + { + return DateTime.IsLeapYear(value.Year); + } + /// /// A representing the final occurence of . public static DateTime Last(this DateTime value, DayOfWeek dayOfWeek) diff --git a/X10D/src/Time/DateTimeOffsetExtensions.cs b/X10D/src/Time/DateTimeOffsetExtensions.cs index 97df8f7..4d4840f 100644 --- a/X10D/src/Time/DateTimeOffsetExtensions.cs +++ b/X10D/src/Time/DateTimeOffsetExtensions.cs @@ -57,6 +57,19 @@ public static class DateTimeOffsetExtensions return value.AddDays(1 - value.Day); } + /// + /// Returns a value indicating whether the year represented by the current is a leap year. + /// + /// The date whose year to check. + /// + /// if the year represented by is a leap year; otherwise, + /// . + /// + public static bool IsLeapYear(this DateTimeOffset value) + { + return DateTime.IsLeapYear(value.Year); + } + /// /// Gets a date representing the final occurence of a specified day of the week in the current month. /// diff --git a/X10D/src/Time/Int16Extensions.cs b/X10D/src/Time/Int16Extensions.cs index 382c6e3..34b9bf2 100644 --- a/X10D/src/Time/Int16Extensions.cs +++ b/X10D/src/Time/Int16Extensions.cs @@ -1,10 +1,39 @@ -namespace X10D.Time; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; +using X10D.Math; + +namespace X10D.Time; /// /// Time-related extension methods for . /// public static class Int16Extensions { + /// + /// Returns a value indicating whether the current integer, representing a year, is a leap year. + /// + /// The value whose leap year status to check. + /// + /// if refers to a leap year; otherwise, . + /// + /// is 0. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public static bool IsLeapYear(this short value) + { + if (value == 0) + { + throw new ArgumentOutOfRangeException(nameof(value), ExceptionMessages.YearCannotBeZero); + } + + if (value < 0) + { + value++; + } + + return value.Mod(4) == 0 && (value.Mod(100) != 0 || value.Mod(400) == 0); + } + /// /// Converts a Unix time expressed as the number of milliseconds that have elapsed since 1970-01-01T00:00:00Z to a /// value. diff --git a/X10D/src/Time/Int32Extensions.cs b/X10D/src/Time/Int32Extensions.cs index 051cbf1..9cad53c 100644 --- a/X10D/src/Time/Int32Extensions.cs +++ b/X10D/src/Time/Int32Extensions.cs @@ -1,10 +1,39 @@ -namespace X10D.Time; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; +using X10D.Math; + +namespace X10D.Time; /// /// Time-related extension methods for . /// public static class Int32Extensions { + /// + /// Returns a value indicating whether the current integer, representing a year, is a leap year. + /// + /// The value whose leap year status to check. + /// + /// if refers to a leap year; otherwise, . + /// + /// is 0. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public static bool IsLeapYear(this int value) + { + if (value == 0) + { + throw new ArgumentOutOfRangeException(nameof(value), ExceptionMessages.YearCannotBeZero); + } + + if (value < 0) + { + value++; + } + + return value.Mod(4) == 0 && (value.Mod(100) != 0 || value.Mod(400) == 0); + } + /// /// Converts a Unix time expressed as the number of milliseconds that have elapsed since 1970-01-01T00:00:00Z to a /// value. diff --git a/X10D/src/Time/Int64Extensions.cs b/X10D/src/Time/Int64Extensions.cs index 114d79b..9135b35 100644 --- a/X10D/src/Time/Int64Extensions.cs +++ b/X10D/src/Time/Int64Extensions.cs @@ -1,10 +1,39 @@ -namespace X10D.Time; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; +using X10D.Math; + +namespace X10D.Time; /// /// Time-related extension methods for . /// public static class Int64Extensions { + /// + /// Returns a value indicating whether the current integer, representing a year, is a leap year. + /// + /// The value whose leap year status to check. + /// + /// if refers to a leap year; otherwise, . + /// + /// is 0. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public static bool IsLeapYear(this long value) + { + if (value == 0) + { + throw new ArgumentOutOfRangeException(nameof(value), ExceptionMessages.YearCannotBeZero); + } + + if (value < 0) + { + value++; + } + + return value.Mod(4) == 0 && (value.Mod(100) != 0 || value.Mod(400) == 0); + } + /// /// Converts a Unix time expressed as the number of milliseconds that have elapsed since 1970-01-01T00:00:00Z to a /// value. diff --git a/X10D/src/Time/SByteExtensions.cs b/X10D/src/Time/SByteExtensions.cs index dd0f2f6..e66cc51 100644 --- a/X10D/src/Time/SByteExtensions.cs +++ b/X10D/src/Time/SByteExtensions.cs @@ -1,4 +1,8 @@ -namespace X10D.Time; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; +using X10D.Math; + +namespace X10D.Time; /// /// Time-related extension methods for . @@ -6,6 +10,31 @@ [CLSCompliant(false)] public static class SByteExtensions { + /// + /// Returns a value indicating whether the current integer, representing a year, is a leap year. + /// + /// The value whose leap year status to check. + /// + /// if refers to a leap year; otherwise, . + /// + /// is 0. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public static bool IsLeapYear(this sbyte value) + { + if (value == 0) + { + throw new ArgumentOutOfRangeException(nameof(value), ExceptionMessages.YearCannotBeZero); + } + + if (value < 0) + { + value++; + } + + return value.Mod(4) == 0 && value.Mod(100) != 0; // mod 400 not required, sbyte.MaxValue is 127 anyway + } + /// /// Converts a Unix time expressed as the number of milliseconds that have elapsed since 1970-01-01T00:00:00Z to a /// value. diff --git a/X10D/src/Time/UInt16Extensions.cs b/X10D/src/Time/UInt16Extensions.cs index f936202..2931171 100644 --- a/X10D/src/Time/UInt16Extensions.cs +++ b/X10D/src/Time/UInt16Extensions.cs @@ -1,4 +1,7 @@ -namespace X10D.Time; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; + +namespace X10D.Time; /// /// Time-related extension methods for . @@ -6,6 +9,26 @@ [CLSCompliant(false)] public static class UInt16Extensions { + /// + /// Returns a value indicating whether the current integer, representing a year, is a leap year. + /// + /// The value whose leap year status to check. + /// + /// if refers to a leap year; otherwise, . + /// + /// is 0. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public static bool IsLeapYear(this ushort value) + { + if (value == 0) + { + throw new ArgumentOutOfRangeException(nameof(value), ExceptionMessages.YearCannotBeZero); + } + + return value % 4 == 0 && (value % 100 != 0 || value % 400 == 0); + } + /// /// Returns a that represents this value as the number of ticks. /// diff --git a/X10D/src/Time/UInt32Extensions.cs b/X10D/src/Time/UInt32Extensions.cs index fcf8296..f305e33 100644 --- a/X10D/src/Time/UInt32Extensions.cs +++ b/X10D/src/Time/UInt32Extensions.cs @@ -1,4 +1,7 @@ -namespace X10D.Time; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; + +namespace X10D.Time; /// /// Time-related extension methods for . @@ -6,6 +9,26 @@ [CLSCompliant(false)] public static class UInt32Extensions { + /// + /// Returns a value indicating whether the current integer, representing a year, is a leap year. + /// + /// The value whose leap year status to check. + /// + /// if refers to a leap year; otherwise, . + /// + /// is 0. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public static bool IsLeapYear(this uint value) + { + if (value == 0) + { + throw new ArgumentOutOfRangeException(nameof(value), ExceptionMessages.YearCannotBeZero); + } + + return value % 4 == 0 && (value % 100 != 0 || value % 400 == 0); + } + /// /// Returns a that represents this value as the number of ticks. /// diff --git a/X10D/src/Time/UInt64Extensions.cs b/X10D/src/Time/UInt64Extensions.cs index 64ff6f7..a58de5e 100644 --- a/X10D/src/Time/UInt64Extensions.cs +++ b/X10D/src/Time/UInt64Extensions.cs @@ -1,4 +1,7 @@ -namespace X10D.Time; +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; + +namespace X10D.Time; /// /// Time-related extension methods for . @@ -6,6 +9,26 @@ [CLSCompliant(false)] public static class UInt64Extensions { + /// + /// Returns a value indicating whether the current integer, representing a year, is a leap year. + /// + /// The value whose leap year status to check. + /// + /// if refers to a leap year; otherwise, . + /// + /// is 0. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public static bool IsLeapYear(this ulong value) + { + if (value == 0) + { + throw new ArgumentOutOfRangeException(nameof(value), ExceptionMessages.YearCannotBeZero); + } + + return value % 4 == 0 && (value % 100 != 0 || value % 400 == 0); + } + /// /// Returns a that represents this value as the number of ticks. ///