How to get the start and end times of a day

C#Datetime

C# Problem Overview


In my C# app, I pass a string variable that is of format yyyymmdd-yyyymmdd that represents a from and to date. I want to get the start and end times for these dates respectively. Currently I have the below code but was wondering if there was more of an elegant solution?

So for pdr = 20090521-20090523 would get "20090521 00:00:00" and "20090523 23:59:59"

private void ValidateDatePeriod(string pdr, out DateTime startDate, 
                                out DateTime endDate)
{
    string[] dates = pdr.Split('-');

    if (dates.Length != 2)
    {
        throw new Exception("Date period is of incorrect format");
    }

    if (dates[0].Length != 8 || dates[1].Length != 8)
    {
        throw new Exception("Split date periods are of incorrect format");
    }

    startDate = DateTime.ParseExact(dates[0] + " 00:00:00", 
        "yyyyMMdd HH:mm:ss", null);
    endDate = DateTime.ParseExact(dates[1] + "23:59:59", 
        "yyyyMMdd HH::mm:ss", null);
}

C# Solutions


Solution 1 - C#

I am surprised to see how an incorrect answer received so many upvotes:

Wrong value

The correct version would be as follows:

public static DateTime StartOfDay(this DateTime theDate)
{
    return theDate.Date;
}

public static DateTime EndOfDay(this DateTime theDate)
{
    return theDate.Date.AddDays(1).AddTicks(-1);
}

Solution 2 - C#

You could define two extension methods somewhere, in a utility class like so :

public static DateTime EndOfDay(this DateTime date)
{
    return new DateTime(date.Year, date.Month, date.Day, 23, 59, 59, 999);
}

public static DateTime StartOfDay(this DateTime date)
{
    return new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, 0);
}

And then use them in code like so :

public DoSomething()
{
    DateTime endOfThisDay = DateTime.Now.EndOfDay();
}

Solution 3 - C#

If you are only worried about .Net precision...

startDate = DateTime.ParseExact(dates[0], "yyyyMMdd");
endDate = DateTime.ParseExact(dates[1], "yyyyMMdd").AddTicks(-1).AddDays(1);

You really don't need to concatenate extra values onto the string for the time portion.


As an addendum, if you are using this for a query against, for example, a database...

startDate = DateTime.ParseExact(dates[0], "yyyyMMdd");
endDate = DateTime.ParseExact(dates[1], "yyyyMMdd").AddDays(1);

With a query of...

WHERE "startDate" >= @startDate AND "endDate" < @endDate

Then the precision issues noted in the comments won't really matter. The endDate in this case would not be part of the range, but the outside boundary.

Solution 4 - C#

public static class DateTimeExtension {        
    public static DateTime StartOfTheDay(this DateTime d) => new DateTime(d.Year, d.Month, d.Day, 0, 0,0);
    public static DateTime EndOfTheDay(this DateTime d) => new DateTime(d.Year, d.Month, d.Day, 23, 59,59);
}

Solution 5 - C#

The DateTime object has a property called Date which will return just the date portion. (The time portion is defaulted to 12:00 am).

I would recommend as a more elegant solution (IMHO) that if you want to allow any datetime on the last day, then you add 1 day to the date, and compare to allow times greater than or equal to the start date, but strictly less than the end date (plus 1 day).

// Calling code.  beginDateTime and endDateTime are already set.
// beginDateTime and endDateTime are inclusive.
// targetDateTime is the date you want to check.
beginDateTime = beginDateTime.Date;
endDateTime = endDateTime.Date.AddDays(1);

if ( beginDateTime <= targetDateTime &&
     targetDateTime < endDateTime )
   // Do something.

Solution 6 - C#

I use the following in C#

public static DateTime GetStartOfDay(DateTime dateTime)
{
    return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 0, 0, 0, 0);
}
public static DateTime GetEndOfDay(DateTime dateTime)
{
    return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59, 999);
}

Then in MS SQL I do the following:

if datepart(ms, @dateEnd) = 0
   set @dateEnd = dateadd(ms, -3, @dateEnd)

This will result in MS SQL time of 23:59:59.997 which is the max time before becoming the next day.

You could simply use:

new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59, 999);

Which will work in MS SQL, but this is not as accurate in .Net side.

Solution 7 - C#

That's pretty much what I would do, with some small tweaks (really no big deal, just nitpicking):

  • The TryParse()/TryParseExact() methods should be used which return false instead of throwing exceptions.
  • FormatException is more specific than Exception
  • No need to check for Length == 8, because ParseExact()/TryParseExact() will do this
  • "00:00:00" and "23:59:59" are not needed
  • return true/false is you were able to parse, instead of throwing an exception (remember to check value returned from this method!)

Code:

private bool ValidateDatePeriod(string pdr, out DateTime startDate, 
						out DateTime endDate)
{
   string[] dates = pdr.Split('-');

   if (dates.Length != 2)
   {
	   return false;
   }

   // no need to check for Length == 8 because the following will do it anyway
   // no need for "00:00:00" or "23:59:59" either, I prefer AddDays(1)

   if(!DateTime.TryParseExact(dates[0], "yyyyMMdd", null, DateTimeStyles.None, out startDate))
	  return false;

   if(!DateTime.TryParseExact(dates[1], "yyyyMMdd", null, DateTimeStyles.None, out endDate))
	  return false;

   endDate = endDate.AddDays(1);
   return true;
}

Solution 8 - C#

I think we're doing it wrong. There is no such thing as the end of the day. AddTick(-1) only works under the convention that there are no time intervals smaller than a tick. Which is implementation dependent. Admittedly the question comes with a reference implementation, namely the .Net Framework DateTime class, but still we should take this as a clue that the function we really want is not EndOfDay() but StartOfNextDay()

public static DateTime StartOfNextDay(this DateTime date)
{
    return date.Date.AddDays(1);
}

Solution 9 - C#

For SQL Server (version 2008 R2 tested) this ranges works.

StarDate '2016-01-11 00:00:01.990' EndDate '2016-01-19 23:59:59.990'

Seems like ticks is greater that the last second of day and automatically round to next day. So i test and works, i made a dummy table with two dates for check what values is sql server catching and inserting in the stored procedure those parameters.

Solution 10 - C#

In Java 8, you can do it using LocalDate as follows:

    LocalDate localDateStart = LocalDate.now();
    Date startDate = Date.from(localDateStart.atStartOfDay(ZoneId.systemDefault()).toInstant());

    LocalDate localDateEnd = localDateStart.plusDays(1);
    Date endDate = Date.from(localDateEnd.atStartOfDay(ZoneId.systemDefault()).toInstant());

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavidView Question on Stackoverflow
Solution 1 - C#anar khalilovView Answer on Stackoverflow
Solution 2 - C#Andrei RîneaView Answer on Stackoverflow
Solution 3 - C#Tracker1View Answer on Stackoverflow
Solution 4 - C#Solarev SergeyView Answer on Stackoverflow
Solution 5 - C#Matt BrunellView Answer on Stackoverflow
Solution 6 - C#Leon van WykView Answer on Stackoverflow
Solution 7 - C#LucasView Answer on Stackoverflow
Solution 8 - C#Chris F CarrollView Answer on Stackoverflow
Solution 9 - C#Ricardo MuñozView Answer on Stackoverflow
Solution 10 - C#KayVView Answer on Stackoverflow