Skip to content

Commit a5facb1

Browse files
committed
Added DateTime extensions for Start and End conversions for day, week, month and year
1 parent 305f8ed commit a5facb1

3 files changed

Lines changed: 296 additions & 0 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace MADE.Data.Converters.Constants
2+
{
3+
using System;
4+
5+
/// <summary>
6+
/// Defines a collection of constants for <see cref="DateTime"/> objects.
7+
/// </summary>
8+
public static class DateTimeConstants
9+
{
10+
/// <summary>
11+
/// Defines the time at the end of a day.
12+
/// </summary>
13+
public static readonly TimeSpan EndOfDayTime = new TimeSpan(1, 0, 0, 0).Subtract(TimeSpan.FromTicks(1));
14+
}
15+
}

src/MADE.Data.Converters/Extensions/DateTimeExtensions.cs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,105 @@ public static int ToCurrentAge(this DateTime startingDate)
3030
return yearDifference;
3131
}
3232

33+
/// <summary>
34+
/// Rounds a <see cref="DateTime"/> value to its nearest hour.
35+
/// <para>
36+
/// This is determined by the half hour of each hour, rounding up or down.
37+
/// </para>
38+
/// </summary>
39+
/// <param name="dateTime">The <see cref="DateTime"/> to round.</param>
40+
/// <returns>The updated <see cref="DateTime"/>.</returns>
41+
public static DateTime ToNearestHour(this DateTime dateTime)
42+
{
43+
int hour = dateTime.Minute < 30
44+
? dateTime.Hour
45+
: dateTime.Hour + 1;
46+
47+
return hour == 24
48+
? new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 0, 0, 0).AddDays(1)
49+
: new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, hour, 0, 0);
50+
}
51+
52+
/// <summary>
53+
/// Gets the start of the day represented by the specified <see cref="DateTime"/> object.
54+
/// </summary>
55+
/// <param name="dateTime">The <see cref="DateTime"/>.</param>
56+
/// <returns>A new object with the same date as this instance, and the time value set to midnight.</returns>
57+
public static DateTime StartOfDay(this DateTime dateTime)
58+
{
59+
return dateTime.Date;
60+
}
61+
62+
/// <summary>
63+
/// Gets the end of the day represented by the specified <see cref="DateTime"/> object.
64+
/// </summary>
65+
/// <param name="dateTime">The <see cref="DateTime"/>.</param>
66+
/// <returns>A new object with the same date as this instance, and the time value set to just before midnight of the next day.</returns>
67+
public static DateTime EndOfDay(this DateTime dateTime)
68+
{
69+
return dateTime.StartOfDay().AddDays(1).AddTicks(-1);
70+
}
71+
72+
/// <summary>
73+
/// Gets the first day of the week represented by the specified <see cref="DateTime"/> object.
74+
/// </summary>
75+
/// <param name="dateTime">The <see cref="DateTime"/>.</param>
76+
/// <returns>A new object with the first day of the week for this instance, and the time value set to midnight.</returns>
77+
public static DateTime StartOfWeek(this DateTime dateTime)
78+
{
79+
return dateTime.AddDays(-(int)dateTime.DayOfWeek).StartOfDay();
80+
}
81+
82+
/// <summary>
83+
/// Gets the last day of the week represented by the specified <see cref="DateTime"/> object.
84+
/// </summary>
85+
/// <param name="dateTime">The <see cref="DateTime"/>.</param>
86+
/// <returns>A new object with the last day of the week for this instance, and the time value set to just before midnight of the next day.</returns>
87+
public static DateTime EndOfWeek(this DateTime dateTime)
88+
{
89+
return dateTime.StartOfWeek().AddDays(7).EndOfDay();
90+
}
91+
92+
/// <summary>
93+
/// Gets the first day of the month represented by the specified <see cref="DateTime"/> object.
94+
/// </summary>
95+
/// <param name="dateTime">The <see cref="DateTime"/>.</param>
96+
/// <returns>A new object with the first day of the month for this instance, and the time value set to midnight.</returns>
97+
public static DateTime StartOfMonth(this DateTime dateTime)
98+
{
99+
return new DateTime(dateTime.Year, dateTime.Month, 1);
100+
}
101+
102+
/// <summary>
103+
/// Gets the last day of the month represented by the specified <see cref="DateTime"/> object.
104+
/// </summary>
105+
/// <param name="dateTime">The <see cref="DateTime"/>.</param>
106+
/// <returns>A new object with the last day of the month for this instance, and the time value set to just before midnight of the next day.</returns>
107+
public static DateTime EndOfMonth(this DateTime dateTime)
108+
{
109+
return dateTime.StartOfMonth().AddMonths(1).AddDays(-1).EndOfDay();
110+
}
111+
112+
/// <summary>
113+
/// Gets the first day of the year represented by the specified <see cref="DateTime"/> object.
114+
/// </summary>
115+
/// <param name="dateTime">The <see cref="DateTime"/>.</param>
116+
/// <returns>A new object with the first day of the year for this instance, and the time value set to midnight.</returns>
117+
public static DateTime StartOfYear(this DateTime dateTime)
118+
{
119+
return new DateTime(dateTime.Year, 1, 1);
120+
}
121+
122+
/// <summary>
123+
/// Gets the last day of the year represented by the specified <see cref="DateTime"/> object.
124+
/// </summary>
125+
/// <param name="dateTime">The <see cref="DateTime"/>.</param>
126+
/// <returns>A new object with the last day of the year for this instance, and the time value set to just before midnight of the next day.</returns>
127+
public static DateTime EndOfYear(this DateTime dateTime)
128+
{
129+
return dateTime.StartOfYear().AddYears(1).AddDays(-1).EndOfDay();
130+
}
131+
33132
/// <summary>
34133
/// Sets the time value of a nullable date/time value.
35134
/// </summary>

tests/MADE.Data.Converters.Tests/Tests/DateTimeExtensionsTests.cs

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ namespace MADE.Data.Converters.Tests.Tests
22
{
33
using System;
44
using System.Diagnostics.CodeAnalysis;
5+
using MADE.Data.Converters.Constants;
56
using MADE.Data.Converters.Extensions;
67
using NUnit.Framework;
78
using Shouldly;
@@ -132,5 +133,186 @@ public void ShouldSetDateTimeIfProvidedTimeAsHoursMinutesSecondsAndMilliseconds(
132133
dateTime.TimeOfDay.ShouldBe(expectedTime);
133134
}
134135
}
136+
137+
public class WhenRoundingToNearestHour
138+
{
139+
[Test]
140+
public void ShouldRoundUpIfAfterHalfHour()
141+
{
142+
// Arrange
143+
int expectedHour = 10;
144+
var dateTime = new DateTime(2021, 5, 12, 9, 31, 0);
145+
146+
// Act
147+
DateTime nearestHour = dateTime.ToNearestHour();
148+
149+
// Assert
150+
nearestHour.Hour.ShouldBe(expectedHour);
151+
}
152+
153+
[Test]
154+
public void ShouldRoundDownIfBeforeHalfHour()
155+
{
156+
// Arrange
157+
int expectedHour = 9;
158+
var dateTime = new DateTime(2021, 5, 12, 9, 29, 0);
159+
160+
// Act
161+
DateTime nearestHour = dateTime.ToNearestHour();
162+
163+
// Assert
164+
nearestHour.Hour.ShouldBe(expectedHour);
165+
}
166+
}
167+
168+
public class WhenGettingStartOfDay
169+
{
170+
[Test]
171+
public void ShouldReturnDateTimeAtMidnight()
172+
{
173+
// Arrange
174+
var expectedTime = new TimeSpan(0, 0, 0);
175+
var dateTime = new DateTime(2021, 5, 12, 9, 29, 0);
176+
177+
// Act
178+
DateTime startOfDay = dateTime.StartOfDay();
179+
180+
// Assert
181+
startOfDay.Date.ShouldBe(dateTime.Date);
182+
startOfDay.TimeOfDay.ShouldBe(expectedTime);
183+
}
184+
}
185+
186+
public class WhenGettingEndOfDay
187+
{
188+
[Test]
189+
public void ShouldReturnDateTimeAtJustBeforeMidnight()
190+
{
191+
// Arrange
192+
TimeSpan expectedTime = DateTimeConstants.EndOfDayTime;
193+
var dateTime = new DateTime(2021, 5, 12, 9, 29, 0);
194+
195+
// Act
196+
DateTime endOfDay = dateTime.EndOfDay();
197+
198+
// Assert
199+
endOfDay.Date.ShouldBe(dateTime.Date);
200+
endOfDay.TimeOfDay.ShouldBe(expectedTime);
201+
}
202+
}
203+
204+
public class WhenGettingStartOfWeek
205+
{
206+
[Test]
207+
public void ShouldReturnFirstDayOfWeekAtMidnight()
208+
{
209+
// Arrange
210+
var expectedDate = new DateTime(2021, 5, 9);
211+
var expectedTime = new TimeSpan(0, 0, 0);
212+
var dateTime = new DateTime(2021, 05, 12, 9, 29, 0);
213+
214+
// Act
215+
DateTime startOfDay = dateTime.StartOfWeek();
216+
217+
// Assert
218+
startOfDay.Date.ShouldBe(expectedDate.Date);
219+
startOfDay.TimeOfDay.ShouldBe(expectedTime);
220+
}
221+
}
222+
223+
public class WhenGettingEndOfWeek
224+
{
225+
[Test]
226+
public void ShouldReturnLastDayOfWeekAtJustBeforeMidnight()
227+
{
228+
// Arrange
229+
var expectedDate = new DateTime(2021, 5, 16);
230+
TimeSpan expectedTime = DateTimeConstants.EndOfDayTime;
231+
var dateTime = new DateTime(2021, 05, 12, 9, 29, 0);
232+
233+
// Act
234+
DateTime endOfDay = dateTime.EndOfWeek();
235+
236+
// Assert
237+
endOfDay.Date.ShouldBe(expectedDate.Date);
238+
endOfDay.TimeOfDay.ShouldBe(expectedTime);
239+
}
240+
}
241+
242+
public class WhenGettingStartOfMonth
243+
{
244+
[Test]
245+
public void ShouldReturnFirstDayOfMonthAtMidnight()
246+
{
247+
// Arrange
248+
var expectedDate = new DateTime(2021, 5, 1);
249+
var expectedTime = new TimeSpan(0, 0, 0);
250+
var dateTime = new DateTime(2021, 05, 12, 9, 29, 0);
251+
252+
// Act
253+
DateTime startOfDay = dateTime.StartOfMonth();
254+
255+
// Assert
256+
startOfDay.Date.ShouldBe(expectedDate.Date);
257+
startOfDay.TimeOfDay.ShouldBe(expectedTime);
258+
}
259+
}
260+
261+
public class WhenGettingEndOfMonth
262+
{
263+
[Test]
264+
public void ShouldReturnLastDayOfMonthAtJustBeforeMidnight()
265+
{
266+
// Arrange
267+
var expectedDate = new DateTime(2021, 5, 31);
268+
TimeSpan expectedTime = DateTimeConstants.EndOfDayTime;
269+
var dateTime = new DateTime(2021, 05, 12, 9, 29, 0);
270+
271+
// Act
272+
DateTime endOfDay = dateTime.EndOfMonth();
273+
274+
// Assert
275+
endOfDay.Date.ShouldBe(expectedDate.Date);
276+
endOfDay.TimeOfDay.ShouldBe(expectedTime);
277+
}
278+
}
279+
280+
public class WhenGettingStartOfYear
281+
{
282+
[Test]
283+
public void ShouldReturnFirstDayOfYearAtMidnight()
284+
{
285+
// Arrange
286+
var expectedDate = new DateTime(2021, 1, 1);
287+
var expectedTime = new TimeSpan(0, 0, 0);
288+
var dateTime = new DateTime(2021, 05, 12, 9, 29, 0);
289+
290+
// Act
291+
DateTime startOfDay = dateTime.StartOfYear();
292+
293+
// Assert
294+
startOfDay.Date.ShouldBe(expectedDate.Date);
295+
startOfDay.TimeOfDay.ShouldBe(expectedTime);
296+
}
297+
}
298+
299+
public class WhenGettingEndOfYear
300+
{
301+
[Test]
302+
public void ShouldReturnLastDayOfYearAtJustBeforeMidnight()
303+
{
304+
// Arrange
305+
var expectedDate = new DateTime(2021, 12, 31);
306+
TimeSpan expectedTime = DateTimeConstants.EndOfDayTime;
307+
var dateTime = new DateTime(2021, 05, 12, 9, 29, 0);
308+
309+
// Act
310+
DateTime endOfDay = dateTime.EndOfYear();
311+
312+
// Assert
313+
endOfDay.Date.ShouldBe(expectedDate.Date);
314+
endOfDay.TimeOfDay.ShouldBe(expectedTime);
315+
}
316+
}
135317
}
136318
}

0 commit comments

Comments
 (0)