2009-05-24 3 views
35

В моем приложении C# я передаю строковую переменную, которая имеет формат 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); 
} 
+0

Как уже отмечалось, EndOfDay, вероятно, является ненужной и неточной конструкцией, поскольку она не имеет определенного момента времени, за исключением, возможно, завтрашнего StartOfDay. – user420667

ответ

13

Если вы беспокоитесь только о точности .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 в этом случае не будет частью диапазона, а внешней границей.

+0

NB: если вы работаете с базой данных, вам, вероятно, придется прочитать мелкий шрифт с точностью до конца дня. Примером, который я ударил, был тип SQL Server DateTime. Это точно до 3 миллисекунд, поэтому конец дня становится .AddMilliseconds (-3) –

+2

@ChrisFCarroll Лично я предпочитаю использовать 'dtm> = start && dtm Tracker1

+0

Я думаю, вы заставили меня понять, что «конец дня» на самом деле является несуществующим понятием, и, следовательно, мы делаем это неправильно. Использование '

9

Объект 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. 
+0

Я хотел вернуть 2 datetimes из разбора строки, поэтому вызывающий метод мог бы использовать эти даты для запроса моего db. – David

+1

@Matt: ваш совет особенно звучит, если времена могут иметь подсезонное разрешение. –

4

Это довольно много, что я хотел бы сделать, с некоторыми небольшими ухищрений (на самом деле нет ничего особенного, просто придирки):

  • должны быть использованы TryParse()/TryParseExact() методы, которые возвращают false вместо того, чтобы бросать исключения ,
  • FormatException более специфичен, чем Exception
  • Нет необходимости проверять Length == 8, потому что ParseExact()/TryParseExact() сделает это
  • "00:00:00" и "23:59:59" не нужны
  • возвращение 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; 
} 
+0

благодарит за комментарии. хорошо знать, что я был на правильном пути и благодарен за трюки – David

33

Можно определить два метода расширения где-то, в служебный класс следующим образом:

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(); 
} 
+3

Приятный ответ, но неверный. Пожалуйста, см. Снимок экрана, который я предоставил, чтобы узнать, почему. –

+1

Действительно. Используйте Анара Халилова, лучше. –

+0

http://stackoverflow.com/a/20565672/1775459 – Vadim

103

Я удивлен видеть, как incorrect answer получили так много 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); 
} 
+2

как упоминается @Chris F Carroll, -1 галочка может быть и неправильной. – liang

+2

@liang, он упомянул: «AddTick (-1) работает только по соглашению о том, что временных интервалов меньше, чем галочка». Есть ли меньше времени в .NET? –

+3

Он привел пример при работе с базой данных. Реализация базы данных различна. Когда в этих сценариях -1 тик, возможно, не конец дня. По крайней мере, нельзя полагаться на равное сравнение. В том же духе плавающих чисел вы не можете сказать, что является самым большим плавающим числом, которое меньше надежного целого, которое зависит от деталей реализации. Скорее больше/меньше, вероятно, лучше. – liang

2

Я думаю, что мы делаем это неправильно. Нет такой вещи, как конец дня. AddTick(-1) работает только по соглашению о том, что временных интервалов меньше, чем галочка. Это зависит от реализации. Правда, возникает вопрос с эталонной реализации, а именно .Net Framework DateTime класса, но все же мы должны принять это как признак того, что функция мы действительно хотим не EndOfDay() но StartOfNextDay()

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

. Почему мы не делаем это AddSeconds (-1), а не Add Ticks? Последняя секунда дня достаточно точна для большинства сценариев. – liang

2

Я использую следующие в 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); 
} 

Затем в 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 стороне.

0

Для SQL Server (версия 2008 R2 протестирована) эти диапазоны работают.

звездного '2016-01-11 00: 00: 01,990' EndDate '2016-01-19 23: 59: 59,990'

Похож тиками больше, что последняя второй день и автоматически вокруг к на следующий день. Поэтому я тестирую и работаю, я создал фиктивную таблицу с двумя датами для проверки того, какие значения занимает sql-сервер, и вставляя в хранимую процедуру эти параметры.

Смежные вопросы