Как обрезать миллисекунды от.NET DateTime
Я пытаюсь сравнить отметку времени из входящего запроса с сохраненным значением базы данных. Конечно, SQL Server сохраняет некоторую точность времени в миллисекундах, а при чтении в.NET DateTime он включает эти миллисекунды. Однако входящий запрос к системе не обеспечивает такой точности, поэтому мне нужно просто отбросить миллисекунды.
Мне кажется, что я упускаю что-то очевидное, но я не нашел элегантного способа сделать это (C#).
18 ответов
Следующее будет работать для DateTime, который имеет дробные миллисекунды, а также сохраняет свойство Kind (Local, Utc или Undefined).
DateTime dateTime = ... anything ...
dateTime = new DateTime(
dateTime.Ticks - (dateTime.Ticks % TimeSpan.TicksPerSecond),
dateTime.Kind
);
или эквивалент и короче:
dateTime = dateTime.AddTicks( - (dateTime.Ticks % TimeSpan.TicksPerSecond));
Это можно обобщить в метод расширения:
public static DateTime Truncate(this DateTime dateTime, TimeSpan timeSpan)
{
if (timeSpan == TimeSpan.Zero) return dateTime; // Or could throw an ArgumentException
if (dateTime == DateTime.MinValue || dateTime == DateTime.MaxValue) return dateTime; // do not modify "guard" values
return dateTime.AddTicks(-(dateTime.Ticks % timeSpan.Ticks));
}
который используется следующим образом:
dateTime = dateTime.Truncate(TimeSpan.FromMilliseconds(1)); // Truncate to whole ms
dateTime = dateTime.Truncate(TimeSpan.FromSeconds(1)); // Truncate to whole second
dateTime = dateTime.Truncate(TimeSpan.FromMinutes(1)); // Truncate to whole minute
...
var date = DateTime.Now;
date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Kind);
Вот метод расширения, основанный на предыдущем ответе, который позволит вам усечь любое разрешение...
Использование:
DateTime myDateSansMilliseconds = myDate.Truncate(TimeSpan.TicksPerSecond);
DateTime myDateSansSeconds = myDate.Truncate(TimeSpan.TicksPerMinute)
Учебный класс:
public static class DateTimeUtils
{
/// <summary>
/// <para>Truncates a DateTime to a specified resolution.</para>
/// <para>A convenient source for resolution is TimeSpan.TicksPerXXXX constants.</para>
/// </summary>
/// <param name="date">The DateTime object to truncate</param>
/// <param name="resolution">e.g. to round to nearest second, TimeSpan.TicksPerSecond</param>
/// <returns>Truncated DateTime</returns>
public static DateTime Truncate(this DateTime date, long resolution)
{
return new DateTime(date.Ticks - (date.Ticks % resolution), date.Kind);
}
}
DateTime d = DateTime.Now;
d = d.AddMilliseconds(-d.Millisecond);
Иногда вы хотите усечь что-то на основе календаря, например, год или месяц. Вот метод расширения, который позволяет вам выбрать любое разрешение.
public enum DateTimeResolution
{
Year, Month, Day, Hour, Minute, Second, Millisecond, Tick
}
public static DateTime Truncate(this DateTime self, DateTimeResolution resolution = DateTimeResolution.Second)
{
switch (resolution)
{
case DateTimeResolution.Year:
return new DateTime(self.Year, 1, 1, 0, 0, 0, 0, self.Kind);
case DateTimeResolution.Month:
return new DateTime(self.Year, self.Month, 1, 0, 0, 0, self.Kind);
case DateTimeResolution.Day:
return new DateTime(self.Year, self.Month, self.Day, 0, 0, 0, self.Kind);
case DateTimeResolution.Hour:
return self.AddTicks(-(self.Ticks % TimeSpan.TicksPerHour));
case DateTimeResolution.Minute:
return self.AddTicks(-(self.Ticks % TimeSpan.TicksPerMinute));
case DateTimeResolution.Second:
return self.AddTicks(-(self.Ticks % TimeSpan.TicksPerSecond));
case DateTimeResolution.Millisecond:
return self.AddTicks(-(self.Ticks % TimeSpan.TicksPerMillisecond));
case DateTimeResolution.Tick:
return self.AddTicks(0);
default:
throw new ArgumentException("unrecognized resolution", "resolution");
}
}
Вместо того чтобы отбрасывать миллисекунды, а затем сравнивать, почему бы не сравнить разницу?
DateTime x; DateTime y;
bool areEqual = (x-y).TotalSeconds == 0;
или же
TimeSpan precision = TimeSpan.FromSeconds(1);
bool areEqual = (x-y).Duration() < precision;
Чтобы округлить до второго:
dateTime.AddTicks(-dateTime.Ticks % TimeSpan.TicksPerSecond)
Заменить TicksPerMinute
округлить до минуты.
Если ваш код чувствителен к производительности, будьте осторожны с
new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second)
Мое приложение тратило 12% процессорного времени в System.DateTime.GetDatePart.
Менее очевидно, но более чем в 2 раза быстрее:
// 10000000 runs
DateTime d = DateTime.Now;
// 484,375ms
d = new DateTime((d.Ticks / TimeSpan.TicksPerSecond) * TimeSpan.TicksPerSecond);
// 1296,875ms
d = d.AddMilliseconds(-d.Millisecond);
Не самое быстрое решение, но простое и понятное:
DateTime d = DateTime.Now;
d = d.Date.AddHours(d.Hour).AddMinutes(d.Minute).AddSeconds(d.Second)
Просто...
//Remove milliseconds
DateTime date = DateTime.Now;
date = DateTime.ParseExact(date.ToString("yyyy-MM-dd HH:mm:ss"), "yyyy-MM-dd HH:mm:ss", null);
И больше...
//Remove seconds
DateTime date = DateTime.Now;
date = DateTime.ParseExact(date.ToString("yyyy-MM-dd HH:mm"), "yyyy-MM-dd HH:mm", null);
//Remove minutes
DateTime date = DateTime.Now;
date = DateTime.ParseExact(date.ToString("yyyy-MM-dd HH"), "yyyy-MM-dd HH", null);
//and go on...
Это моя версия методов расширения, размещенных здесь и в аналогичных вопросах. Это проверяет значение тактов в удобном для чтения виде и сохраняет DateTimeKind исходного экземпляра DateTime. (Это имеет тонкие, но важные побочные эффекты при хранении в базе данных, такой как MongoDB.)
Если истинная цель - усечь DateTime до указанного значения (например, часов / минут / секунд /MS), я рекомендую вместо этого реализовать этот метод расширения в вашем коде. Это гарантирует, что вы можете выполнить только усечение до допустимой точности, и сохраняет важные метаданные DateTimeKind вашего исходного экземпляра:
public static DateTime Truncate(this DateTime dateTime, long ticks)
{
bool isValid = ticks == TimeSpan.TicksPerDay
|| ticks == TimeSpan.TicksPerHour
|| ticks == TimeSpan.TicksPerMinute
|| ticks == TimeSpan.TicksPerSecond
|| ticks == TimeSpan.TicksPerMillisecond;
// https://stackru.com/questions/21704604/have-datetime-now-return-to-the-nearest-second
return isValid
? DateTime.SpecifyKind(
new DateTime(
dateTime.Ticks - (dateTime.Ticks % ticks)
),
dateTime.Kind
)
: throw new ArgumentException("Invalid ticks value given. Only TimeSpan tick values are allowed.");
}
Тогда вы можете использовать такой метод:
DateTime dateTime = DateTime.UtcNow.Truncate(TimeSpan.TicksPerMillisecond);
dateTime.Kind => DateTimeKind.Utc
2 Методы расширения для решений, упомянутых выше
public static bool LiesAfterIgnoringMilliseconds(this DateTime theDate, DateTime compareDate, DateTimeKind kind)
{
DateTime thisDate = new DateTime(theDate.Year, theDate.Month, theDate.Day, theDate.Hour, theDate.Minute, theDate.Second, kind);
compareDate = new DateTime(compareDate.Year, compareDate.Month, compareDate.Day, compareDate.Hour, compareDate.Minute, compareDate.Second, kind);
return thisDate > compareDate;
}
public static bool LiesAfterOrEqualsIgnoringMilliseconds(this DateTime theDate, DateTime compareDate, DateTimeKind kind)
{
DateTime thisDate = new DateTime(theDate.Year, theDate.Month, theDate.Day, theDate.Hour, theDate.Minute, theDate.Second, kind);
compareDate = new DateTime(compareDate.Year, compareDate.Month, compareDate.Day, compareDate.Hour, compareDate.Minute, compareDate.Second, kind);
return thisDate >= compareDate;
}
использование:
bool liesAfter = myObject.DateProperty.LiesAfterOrEqualsIgnoringMilliseconds(startDateTime, DateTimeKind.Utc);
Относительно ответа Диадистиса. Это сработало для меня, за исключением того, что мне пришлось использовать Floor, чтобы удалить дробную часть деления перед умножением. Так,
d = new DateTime((d.Ticks / TimeSpan.TicksPerSecond) * TimeSpan.TicksPerSecond);
становится
d = new DateTime(Math.Floor(d.Ticks / TimeSpan.TicksPerSecond) * TimeSpan.TicksPerSecond);
Я ожидал бы, что деление двух длинных значений приведет к длинному, удалив, таким образом, десятичную часть, но это разрешит его как двойное, оставляя точно такое же значение после умножения.
Eppsy
DateID.Text = DateTime.Today.ToShortDateString();
Use ToShortDateString() //Date 2-02-2016
Use ToShortDateString() // Time
И с помощью
ToLongDateString() // its show 19 February 2016.
:П
Новый метод
String Date = DateTime.Today.ToString("dd-MMM-yyyy");
// определить параметр передачи строки dd-mmm-yyyy return 24-feb-2016
Или показано в текстовом поле
txtDate.Text = DateTime.Today.ToString("dd-MMM-yyyy");
// положить на PageonLoad
Вы можете просто использовать Split
new TimeSpan(new DateTime(1970, 1, 1).Ticks).TotalSeconds.ToString().Split('.')[0]
В моем случае я стремился сохранить TimeSpan из инструмента datetimePicker, не экономя секунды и миллисекунды, и вот решение.
Сначала преобразуйте datetimePicker.value в желаемый формат, мой формат "ЧЧ: мм", а затем преобразуйте его обратно в TimeSpan.
var datetime = datetimepicker1.Value.ToString("HH:mm");
TimeSpan timeSpan = Convert.ToDateTime(datetime).TimeOfDay;
Я знаю, что ответ довольно поздно, но лучший способ избавиться от миллисекунд - это
var currentDateTime = DateTime.Now.ToString("s");
Попробуйте распечатать значение переменной, оно покажет дату и время без миллисекунд.