Вырезать/округлить DateTime до целого, т.е. Hour/Day?

Есть ли какой-либо математический способ сократить DateTime до определенного часа, дня или около того? Совпадает с округлением десятичного числа до int.

Period.Day
Если первоначальное значение было 2011-01-01 13:00:00, оно заканчивается в 2011-01-01 00:00:00

если Period.Hour
Если первоначальное значение было 2011-03-11 13:32:00, оно заканчивается в 2011-03-11 13:00:00

Я думаю о чем-то вроде ниже. Это, конечно, отлично работает, но range -array в любом случае повторяется. Лучше, если бы я мог рассчитывать непосредственно на этой итерации, а не на нее. Но someType не может быть помещен в эту итерацию (это зависит от someType).

if (someType == Period.Day)
  range.ForEach(d => d.time = new DateTime(d.time.Year, d.time.Month, d.time.Day,0,0,0));
if (someType == Period.Hour)
  range.ForEach(d => d.time = new DateTime(d.time.Year, d.time.Month, d.time.Day, d.time.Hour, 0, 0));

Ответ 1

Округление до дня эквивалентно time.Date, округление до ближайшего (вверх по середине) просто ( time + 12hours).Date.

Для округления до полного часа я не могу придумать код, который лучше читать, чем ваш. Для округления до ближайшего часа вы можете применить свой код к time + 30mins.

Вероятно, существует более быстрый метод округления до ближайшего часа:

const Int64 HourInTicks=...;
Int64 timeInTicks=time.Ticks;
Int64 trucatedToHour=timeInTicks-timeInTicks%HourInTicks;

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

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

Ответ 2

Для округления до конца вы можете использовать свойство DateTime.Date.
Чтобы округлить до часа, я боюсь, вам придется либо использовать то, что вы сделали в своем примере, или что-то вроде:

d.Date.AddHours(d.Hour)

Ответ 3

Я сделаю следующее:

private static readonly DateTime Epoch = new DateTime(1970, 1, 1); 
public static DateTime Round(this DateTime d, Period p)
{
    var ts = d - Epoch;

    if (p == Period.Hour)
    {
        var hours = (long)ts.TotalHours;
        return Epoch.AddHours(hours);
    }
    else if (p == Period.Days)
    {
        var days = (long)ts.TotalDays;
        return Epoch.AddDays(days);
    }
    // ...
}

Ответ 4

Я считаю, что следующий код С# будет округлять значение DateTime до ближайшей минуты, и я думаю, что будет легко обобщить его на раунд для других единиц.

//round to nearest minute; add 30 seconds for rounding to nearest minute
effectiveDateTime = effectiveDateTime.AddSeconds(30);
TimeSpan timeComponent = effectiveDateTime.TimeOfDay;
effectiveDateTime = effectiveDateTime.Date;
effectiveDateTime = effectiveDateTime.AddHours(timeComponent.Hours).
     AddMinutes(timeComponent.Minutes);

Ответ 5

Не уверен, что этот подход эффективен, но выглядит довольно неплохо, используя строковый формат (в этом случае сокращение до нескольких часов):

var date = DateTime.UtcNow;
var cutDownDate = Convert.ToDateTime(date.ToString("yyyy-MM-dd hh"));