diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6c4bed6..bde92e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,5 +15,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `IConfiguration` extension methods
- `IServiceCollection` extension methods
- `String` extension methods
+- `DateTime` extension methods
- `IFormFile` extension method (AspNetCore package only)
- `DbSet` extension methods for ISortableEntity interface (EntityFrameworkCore package only)
diff --git a/Neolution.Utilities.UnitTests/Extensions/DateTimeExtensionsTests.cs b/Neolution.Utilities.UnitTests/Extensions/DateTimeExtensionsTests.cs
new file mode 100644
index 0000000..e11d7f4
--- /dev/null
+++ b/Neolution.Utilities.UnitTests/Extensions/DateTimeExtensionsTests.cs
@@ -0,0 +1,181 @@
+namespace Neolution.Utilities.UnitTests.Extensions;
+
+using System.Diagnostics.CodeAnalysis;
+
+///
+/// Unit tests for the class.
+///
+public class DateTimeExtensionsTests
+{
+ ///
+ /// Tests the parameter-less method which requires the time to be exactly 00:00:00.
+ ///
+ /// The year component.
+ /// The month component.
+ /// The day component.
+ /// The hour component.
+ /// The minute component.
+ /// The second component.
+ /// Expected result indicating whether it is exactly midnight.
+ [Theory]
+ [InlineData(2025, 1, 10, 0, 0, 0, true)] // Exact midnight
+ [InlineData(2025, 1, 10, 0, 0, 1, false)] // Midnight + 1 second
+ [InlineData(2025, 1, 10, 0, 1, 0, false)] // 00:01
+ [InlineData(2025, 1, 10, 1, 0, 0, false)] // 01:00
+ [InlineData(2025, 1, 10, 23, 59, 59, false)] // End of day just before midnight
+ public void GivenDateTime_WhenIsMidnightCalled_ThenReturnsExpected(
+ int year, int month, int day, int hour, int minute, int second, bool expected)
+ {
+ // Arrange
+ var dateTime = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Unspecified);
+
+ // Act
+ var result = dateTime.IsMidnight();
+
+ // Assert
+ result.ShouldBe(expected);
+ }
+
+ ///
+ /// Tests with the ignoreSeconds flag.
+ /// Ensures midnight detection works both strictly and when seconds are ignored.
+ ///
+ /// Hour component.
+ /// Minute component.
+ /// Second component.
+ /// Flag indicating whether to ignore seconds.
+ /// Expected result given the flag.
+ [Theory]
+ [InlineData(0, 0, 0, false, true)] // Exact midnight strict
+ [InlineData(0, 0, 1, false, false)] // Not exact midnight strict
+ [InlineData(0, 0, 1, true, true)] // Midnight with seconds ignored
+ [InlineData(0, 1, 0, true, false)] // Minute > 0 cannot be midnight
+ [InlineData(1, 0, 0, true, false)] // Hour > 0 cannot be midnight
+ public void GivenDateTimeAndIgnoreSecondsFlag_WhenIsMidnightCalled_ThenReturnsExpected(
+ int hour, int minute, int second, bool ignoreSeconds, bool expected)
+ {
+ // Arrange
+ var dateTime = new DateTime(2025, 5, 20, hour, minute, second, DateTimeKind.Unspecified);
+
+ // Act
+ var result = dateTime.IsMidnight(ignoreSeconds);
+
+ // Assert
+ result.ShouldBe(expected);
+ }
+
+ ///
+ /// Tests with various months including leap year February.
+ ///
+ /// Year component.
+ /// Month component.
+ /// Day component.
+ /// Expected result (true if end of month).
+ [Theory]
+ [InlineData(2025, 1, 31, true)] // 31-day month end
+ [InlineData(2025, 1, 30, false)]
+ [InlineData(2024, 2, 29, true)] // Leap year February
+ [InlineData(2024, 2, 28, false)]
+ [InlineData(2025, 2, 28, true)] // Non-leap year February
+ [InlineData(2025, 2, 27, false)]
+ [InlineData(2025, 4, 30, true)] // 30-day month end
+ [InlineData(2025, 4, 29, false)]
+ public void GivenDateTime_WhenIsEndOfMonthCalled_ThenReturnsExpected(
+ int year, int month, int day, bool expected)
+ {
+ // Arrange
+ var dateTime = new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Unspecified);
+
+ // Act
+ var result = dateTime.IsEndOfMonth();
+
+ // Assert
+ result.ShouldBe(expected);
+ }
+
+ ///
+ /// Gets the test data for method.
+ ///
+ [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "It's better to have test data next to the test method")]
+ public static TheoryData GivenTargetAndRange_WhenIsInRangeCalled_ThenReturnsExpected_TestData => new()
+ {
+ {
+ // Inside range
+ new DateTime(2025, 5, 15, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 14, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 16, 0, 0, 0, DateTimeKind.Unspecified),
+ true
+ },
+ {
+ // Equal to start
+ new DateTime(2025, 5, 14, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 14, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 16, 0, 0, 0, DateTimeKind.Unspecified),
+ true
+ },
+ {
+ // Equal to end
+ new DateTime(2025, 5, 16, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 14, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 16, 0, 0, 0, DateTimeKind.Unspecified),
+ true
+ },
+ {
+ // Before start
+ new DateTime(2025, 5, 13, 22, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 14, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 16, 0, 0, 0, DateTimeKind.Unspecified),
+ false
+ },
+ {
+ // After end
+ new DateTime(2025, 5, 16, 22, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 14, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 16, 0, 0, 0, DateTimeKind.Unspecified),
+ false
+ },
+ {
+ // Single point range (match)
+ new DateTime(2025, 5, 15, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 15, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 15, 0, 0, 0, DateTimeKind.Unspecified),
+ true
+ },
+ {
+ // Single point range (mismatch)
+ new DateTime(2025, 5, 14, 21, 36, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 15, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 15, 0, 0, 0, DateTimeKind.Unspecified),
+ false
+ },
+ {
+ // Reversed range (start > end) always false
+ new DateTime(2025, 5, 15, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 16, 0, 0, 0, DateTimeKind.Unspecified),
+ new DateTime(2025, 5, 14, 0, 0, 0, DateTimeKind.Unspecified),
+ false
+ },
+ };
+
+ ///
+ /// Tests ensuring:
+ /// - Inclusive start and end boundaries.
+ /// - Dates before and after the range are excluded.
+ /// - Single-point range behavior (start == end).
+ /// - Reversed range (start > end) returns false.
+ ///
+ /// The target date to check.
+ /// The start of the range.
+ /// The end of the range.
+ /// Expected result indicating if target is in range.
+ [Theory]
+ [MemberData(nameof(GivenTargetAndRange_WhenIsInRangeCalled_ThenReturnsExpected_TestData))]
+ public void GivenTargetAndRange_WhenIsInRangeCalled_ThenReturnsExpected(DateTime target, DateTime startDate, DateTime endDate, bool expectedResult)
+ {
+ // Act
+ var result = target.IsInRange(startDate, endDate);
+
+ // Assert
+ result.ShouldBe(expectedResult);
+ }
+}
diff --git a/Neolution.Utilities/Extensions/DateTimeExtensions.cs b/Neolution.Utilities/Extensions/DateTimeExtensions.cs
new file mode 100644
index 0000000..ec8cb44
--- /dev/null
+++ b/Neolution.Utilities/Extensions/DateTimeExtensions.cs
@@ -0,0 +1,48 @@
+namespace Neolution.Utilities.Extensions;
+
+///
+/// The DateTime extension methods.
+///
+public static class DateTimeExtensions
+{
+ ///
+ /// Determines whether the specified value is exactly at midnight (00:00:00).
+ ///
+ /// The to evaluate.
+ /// true if the time component is exactly 00:00:00; otherwise false.
+ public static bool IsMidnight(this DateTime dateTime)
+ => dateTime.IsMidnight(false);
+
+ ///
+ /// Determines whether the specified value represents midnight (00:00),
+ /// optionally ignoring the seconds component.
+ ///
+ /// The to evaluate.
+ ///
+ /// If true, evaluates midnight as any time where hour and minute are zero (00:00), regardless of seconds.
+ /// If false, requires the time to be exactly 00:00:00.
+ ///
+ ///
+ /// true if the time is midnight according to the rule; otherwise false.
+ ///
+ public static bool IsMidnight(this DateTime dateTime, bool ignoreSeconds)
+ => ignoreSeconds ? dateTime.Hour == 0 && dateTime.Minute == 0 : dateTime.TimeOfDay.Ticks == 0;
+
+ ///
+ /// Determines whether the specified value is the end of the month.
+ ///
+ /// The to evaluate.
+ /// true if the specified value is the end of the month; otherwise, false.
+ public static bool IsEndOfMonth(this DateTime dateTime)
+ => dateTime.Day == DateTime.DaysInMonth(dateTime.Year, dateTime.Month);
+
+ ///
+ /// Determines whether the specified value is in range.
+ ///
+ /// The to evaluate.
+ /// The start .
+ /// The end .
+ /// true if the specified value is in range; otherwise, false.
+ public static bool IsInRange(this DateTime dateTime, DateTime startDate, DateTime endDate)
+ => dateTime >= startDate && dateTime <= endDate;
+}