Skip to content

Commit 3fc7631

Browse files
Merge pull request #280 from classyk12/fix/DateTime_Kind
fix: DateTime Kind preservation
2 parents 8ad01e6 + 0adda57 commit 3fc7631

3 files changed

Lines changed: 117 additions & 4 deletions

File tree

src/DateTimeExtensions/GeneralDateTimeExtensions.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public static DateTime SetTime(this DateTime date, int hour, int minute, int sec
126126

127127
public static DateTime SetTime(this DateTime date, int hour, int minute, int second, int millisecond)
128128
{
129-
return new DateTime(date.Year, date.Month, date.Day, hour, minute, second, millisecond);
129+
return new DateTime(date.Year, date.Month, date.Day, hour, minute, second, millisecond, date.Kind);
130130
}
131131

132132
/// <summary>
@@ -137,7 +137,7 @@ public static DateTime SetTime(this DateTime date, int hour, int minute, int sec
137137
/// <returns>The new floored DateTime object</returns>
138138
public static DateTime Floor(this DateTime dt, TimeSpan interval)
139139
{
140-
return dt.AddTicks(-(dt.Ticks%interval.Ticks));
140+
return dt.AddTicks(-(dt.Ticks % interval.Ticks));
141141
}
142142

143143
/// <summary>
@@ -148,7 +148,7 @@ public static DateTime Floor(this DateTime dt, TimeSpan interval)
148148
/// <returns>The new ceilinged DateTime object</returns>
149149
public static DateTime Ceiling(this DateTime dt, TimeSpan interval)
150150
{
151-
return dt.AddTicks(interval.Ticks - (dt.Ticks%interval.Ticks));
151+
return dt.AddTicks(interval.Ticks - (dt.Ticks % interval.Ticks));
152152
}
153153

154154
/// <summary>
@@ -160,7 +160,7 @@ public static DateTime Ceiling(this DateTime dt, TimeSpan interval)
160160
public static DateTime Round(this DateTime dt, TimeSpan interval)
161161
{
162162
var halfIntervalTicks = ((interval.Ticks + 1) >> 1);
163-
return dt.AddTicks(halfIntervalTicks - ((dt.Ticks + halfIntervalTicks)%interval.Ticks));
163+
return dt.AddTicks(halfIntervalTicks - ((dt.Ticks + halfIntervalTicks) % interval.Ticks));
164164
}
165165

166166
/// <summary>

src/DateTimeExtensions/NaturalText/DateDiff.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ public DateDiff(DateTime startDate, DateTime endDate) : this()
5959
Days += daysInMonth - startDate.Day + endDate.Day;
6060
}
6161

62+
//adjust month difference for february and leap years
63+
var daysInMonthForEndDate = DateTime.DaysInMonth(endDate.Year, endDate.Month);
64+
if (daysInMonthForEndDate > 27 && daysInMonthForEndDate <= 29 && Days > 27 && Days <= 29)
65+
{
66+
Months = 0;
67+
Days = 0;
68+
}
69+
6270
if (Months + endDate.Month >= startDate.Month)
6371
{
6472
Months += endDate.Month - startDate.Month;
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using System;
2+
using NUnit.Framework;
3+
4+
namespace DateTimeExtensions.Tests
5+
{
6+
[TestFixture]
7+
public class GeneralDateTimeExtensionsTests
8+
{
9+
[Test]
10+
public void SetTime_Preserves_Utc_Kind()
11+
{
12+
// Arrange
13+
DateTime utcDate = new(2026, 7, 7, 14, 0, 0, DateTimeKind.Utc);
14+
15+
// Act
16+
DateTime result = utcDate.SetTime(15);
17+
Assert.Multiple(() =>
18+
{
19+
20+
// Assert
21+
Assert.That(result.Kind, Is.EqualTo(DateTimeKind.Utc));
22+
Assert.That(result.Hour, Is.EqualTo(15));
23+
Assert.That(result.Minute, Is.EqualTo(0));
24+
Assert.That(result.Second, Is.EqualTo(0));
25+
Assert.That(result.Millisecond, Is.EqualTo(0));
26+
});
27+
}
28+
29+
[Test]
30+
public void SetTime_Preserves_Local_Kind()
31+
{
32+
// Arrange
33+
DateTime localDate = new(2026, 7, 7, 14, 0, 0, DateTimeKind.Local);
34+
35+
// Act
36+
DateTime result = localDate.SetTime(15, 30);
37+
Assert.Multiple(() =>
38+
{
39+
40+
// Assert
41+
Assert.That(result.Kind, Is.EqualTo(DateTimeKind.Local));
42+
Assert.That(result.Hour, Is.EqualTo(15));
43+
Assert.That(result.Minute, Is.EqualTo(30));
44+
});
45+
}
46+
47+
[Test]
48+
public void SetTime_Preserves_Unspecified_Kind()
49+
{
50+
// Arrange
51+
DateTime unspecifiedDate = new(2026, 7, 7, 14, 0, 0, DateTimeKind.Unspecified);
52+
53+
// Act
54+
DateTime result = unspecifiedDate.SetTime(15, 30, 45);
55+
Assert.Multiple(() =>
56+
{
57+
58+
// Assert
59+
Assert.That(result.Kind, Is.EqualTo(DateTimeKind.Unspecified));
60+
Assert.That(result.Hour, Is.EqualTo(15));
61+
Assert.That(result.Minute, Is.EqualTo(30));
62+
Assert.That(result.Second, Is.EqualTo(45));
63+
});
64+
}
65+
66+
[Test]
67+
public void SetTime_With_Milliseconds_Preserves_Kind()
68+
{
69+
// Arrange
70+
DateTime utcDate = new(2026, 7, 7, 14, 0, 0, DateTimeKind.Utc);
71+
72+
// Act
73+
DateTime result = utcDate.SetTime(15, 30, 45, 500);
74+
Assert.Multiple(() =>
75+
{
76+
77+
// Assert
78+
Assert.That(result.Kind, Is.EqualTo(DateTimeKind.Utc));
79+
Assert.That(result.Hour, Is.EqualTo(15));
80+
Assert.That(result.Minute, Is.EqualTo(30));
81+
Assert.That(result.Second, Is.EqualTo(45));
82+
Assert.That(result.Millisecond, Is.EqualTo(500));
83+
});
84+
}
85+
86+
[Test]
87+
[TestCase(DateTimeKind.Utc)]
88+
[TestCase(DateTimeKind.Local)]
89+
[TestCase(DateTimeKind.Unspecified)]
90+
public void SetTime_All_Overloads_Preserve_Kind(DateTimeKind kind)
91+
{
92+
// Arrange
93+
DateTime originalDate = new(2026, 7, 7, 14, 0, 0, kind);
94+
Assert.Multiple(() =>
95+
{
96+
97+
// Act & Assert - Test all overloads
98+
Assert.That(originalDate.SetTime(15).Kind, Is.EqualTo(kind));
99+
Assert.That(originalDate.SetTime(15, 30).Kind, Is.EqualTo(kind));
100+
Assert.That(originalDate.SetTime(15, 30, 45).Kind, Is.EqualTo(kind));
101+
Assert.That(originalDate.SetTime(15, 30, 45, 500).Kind, Is.EqualTo(kind));
102+
});
103+
}
104+
}
105+
}

0 commit comments

Comments
 (0)