Как узнать время начала и окончания дня
В моем приложении на С# я передаю строковую переменную в формате yyyymmdd-yyyymmdd, представляющую дату и дату. Я хочу получить время начала и окончания этих дат соответственно. В настоящее время у меня есть код ниже, но мне было интересно, есть ли более элегантное решение?
Таким образом, для pdr = 20090521-20090523 будет получено "20090521 00:00:00" и "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);
}
Ответы
Ответ 1
Если вас беспокоит только точность .Net...
startDate = DateTime.ParseExact(dates[0], "yyyyMMdd");
endDate = DateTime.ParseExact(dates[1], "yyyyMMdd").AddTicks(-1).AddDays(1);
Вам действительно не нужно конкатенировать дополнительные значения в строке для временной части.
В качестве дополнения, если вы используете это для запроса против, например, базы данных...
startDate = DateTime.ParseExact(dates[0], "yyyyMMdd");
endDate = DateTime.ParseExact(dates[1], "yyyyMMdd").AddDays(1);
С запросом...
WHERE "startDate" >= @startDate AND "endDate" < @endDate
Тогда вопросы точности, отмеченные в комментариях, не будут иметь большого значения. endDate в этом случае не будет частью диапазона, а внешней границей.
Ответ 2
Я удивлен, увидев, как неправильный ответ получил так много upvotes:
![Wrong value]()
Правильная версия будет следующей:
public static DateTime StartOfDay(this DateTime theDate)
{
return theDate.Date;
}
public static DateTime EndOfDay(this DateTime theDate)
{
return theDate.Date.AddDays(1).AddTicks(-1);
}
Ответ 3
Вы можете определить два метода расширения где-нибудь в классе утилиты:
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);
}
И затем используйте их в коде так:
public DoSomething()
{
DateTime endOfThisDay = DateTime.Now.EndOfDay();
}
Ответ 4
Объект DateTime
имеет свойство Date
, которое возвращает только часть даты. (Временная часть по умолчанию установлена до 12:00 утра).
Я бы рекомендовал в качестве более элегантного решения (IMHO): если вы хотите разрешить какое-либо время в последний день, то вы добавляете 1 день к дате и сравниваете, чтобы время, большее или равное дате начала, но строго меньше даты окончания (плюс 1 день).
// 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.
Ответ 5
Это в значительной степени то, что я сделал бы, с некоторыми небольшими настройками (на самом деле неважно, просто nitpicking):
- Следует использовать методы
TryParse()
/TryParseExact()
, которые возвращают false
вместо исключения исключений.
-
FormatException
более конкретный, чем Exception
- Не нужно проверять длину == 8, потому что
ParseExact()
/TryParseExact()
сделает это
-
"00:00:00"
и "23:59:59"
не нужны
- return
true
/false
Вы можете проанализировать, вместо того, чтобы бросать исключение (не забудьте проверить значение, возвращаемое этим методом!)
код:
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;
}
Ответ 6
Я думаю, что мы делаем это неправильно. Нет такой вещи, как конец дня. AddTick(-1)
работает только по соглашению, что нет временных интервалов, меньших галочки. Это зависит от реализации. Разумеется, вопрос связан с эталонной реализацией, а именно с классом .Net Framework DateTime
, но все же мы должны считать это ключом к тому, что функция, которую мы действительно хотим, это не EndOfDay()
, а StartOfNextDay()
public static DateTime StartOfNextDay(this DateTime date)
{
return date.Date.AddDays(1);
}
Ответ 7
Я использую следующее в С#
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);
}
Затем в MS SQL я делаю следующее:
if datepart(ms, @dateEnd) = 0
set @dateEnd = dateadd(ms, -3, @dateEnd)
Это приведет к времени MS SQL 23: 59: 59.997, которое является максимальным временем до того, как станет на следующий день.
Вы можете просто использовать:
new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59, 999);
Что будет работать в MS SQL, но это не так точно на стороне .Net.
Ответ 8
Для SQL Server (версия 2008 R2 протестирована) эти диапазоны работают.
StarDate '2016-01-11 00: 00: 01.990'
EndDate '2016-01-19 23: 59: 59.990'
Кажется, что тики больше, чем последняя секунда дня и автоматически округляются до следующего дня. Так что я тестирую и работаю, я создал фиктивную таблицу с двумя датами для проверки того, какие значения занимает sql-сервер, и вставляя в хранимую процедуру эти параметры.