DateTime 객체 반올림


105

차트 응용 프로그램의 날짜 / 시간을 가장 가까운 간격으로 반올림하고 싶습니다. 모든 수준의 정확성에 대해 반올림을 수행 할 수 있도록 다음과 같은 확장 메서드 서명을 원합니다.

static DateTime Round(this DateTime date, TimeSpan span);

아이디어는 내가 10 분의 시간 범위를 지나면 가장 가까운 10 분 간격으로 반올림된다는 것입니다. 나는 구현에 대해 내 머리를 이해할 수 없으며 당신 중 한 명이 전에 비슷한 것을 작성하거나 사용하기를 바라고 있습니다.

나는 바닥, 천장 또는 가장 가까운 구현이 괜찮다고 생각합니다.

어떤 아이디어?

편집 : @tvanfosson & @ShuggyCoUk 덕분에 구현은 다음과 같습니다.

public static class DateExtensions {
    public static DateTime Round(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;
        return new DateTime(ticks * span.Ticks);
    }
    public static DateTime Floor(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks / span.Ticks);
        return new DateTime(ticks * span.Ticks);
    }
    public static DateTime Ceil(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks + span.Ticks - 1) / span.Ticks;
        return new DateTime(ticks * span.Ticks);
    }
}

그리고 이렇게 불립니다 :

DateTime nearestHour = DateTime.Now.Round(new TimeSpan(1,0,0));
DateTime minuteCeiling = DateTime.Now.Ceil(new TimeSpan(0,1,0));
DateTime weekFloor = DateTime.Now.Floor(new TimeSpan(7,0,0,0));
...

건배!


1
여기에있는 구현 중 일부도 도움이 될 수 있습니다. stackoverflow.com/questions/766626/…
Matt Hamilton


3
새로 생성 된 날짜에 원래 DateTimeKind를 추가하는 것을 잊지 마십시오. 예 : new DateTime (ticks * span.Ticks, date.Kind);
AM

답변:


130

바닥

long ticks = date.Ticks / span.Ticks;

return new DateTime( ticks * span.Ticks );

라운드 (중간 지점에서 위로)

long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;

return new DateTime( ticks * span.Ticks );

천장

long ticks = (date.Ticks + span.Ticks - 1)/ span.Ticks;

return new DateTime( ticks * span.Ticks );

5
최근에 DateTimeKind가 보존되지 않는 문제가 발생했습니다. 각 방법의 마지막 줄에 대한 다음 조정은 제 경우에 도움이되었습니다.return new DateTime(ticks * span.Ticks, date.Kind);
Peet

39

이렇게하면 주어진 간격으로 반올림 할 수 있습니다. 또한 눈금을 나누고 곱하는 것보다 약간 빠릅니다.

public static class DateTimeExtensions
{
  public static DateTime Floor(this DateTime dateTime, TimeSpan interval)
  {
    return dateTime.AddTicks(-(dateTime.Ticks % interval.Ticks));
  }

  public static DateTime Ceiling(this DateTime dateTime, TimeSpan interval)
  {
    var overflow = dateTime.Ticks % interval.Ticks;

    return overflow == 0 ? dateTime : dateTime.AddTicks(interval.Ticks - overflow);
  }

  public static DateTime Round(this DateTime dateTime, TimeSpan interval)
  {
    var halfIntervalTicks = (interval.Ticks + 1) >> 1;

    return dateTime.AddTicks(halfIntervalTicks - ((dateTime.Ticks + halfIntervalTicks) % interval.Ticks));
  }
}

11

반올림을 다음과 같은 경우에도 명확해야합니다.

  1. 간격의 시작, 끝 또는 중간까지
    • 시작이 가장 쉽고 자주 예상되지만 초기 사양에서 명확해야합니다.
  2. 경계 케이스를 반올림하는 방법.
    • 일반적으로 끝이 아닌 중간으로 반올림하는 경우에만 문제가됩니다.
    • 중간으로 반올림하는 것은 편견이없는 답변을 시도 하는 것이므로 편향에서 진정으로 해방 되려면 Bankers Rounding 기술적으로 반올림 과 같은 것을 사용해야합니다 .

실제로 첫 번째 지점에만 관심이있을 가능성이 높지만 이러한 '간단한'질문에서 결과 동작은 실제 세계에서 사용할 때 광범위한 결과를 초래할 수 있습니다 (종종 0에 인접한 간격에서)

tvanfosson의 솔루션은 1에 나열된 모든 경우를 다룹니다. 중간 지점 예는 위쪽으로 치우쳐 있습니다. 이것이 시간 관련 반올림에서 문제가 될지는 의심 스럽다.


3

Ticks를 사용하여 나누고 값을 바닥 / 천장 / 반올림 한 다음 다시 곱하십시오.


-2

시간을 상한값으로 반올림하려는 경우

Console.WriteLine(DateTime.Now.ToString("M/d/yyyy hh:00:00"));

OP는 반환 객체로 DateTime을 요청했습니다.
aj.toulan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.