.NET DateTime에서 밀리 초를 자르는 방법


334

들어오는 요청의 타임 스탬프를 데이터베이스 저장된 값과 비교하려고합니다. 물론 SQL Server는 정시에 밀리 초의 정밀도를 유지하며 .NET DateTime으로 읽을 때 해당 밀리 초를 포함합니다. 그러나 시스템에 들어오는 요청은 그 정밀도를 제공하지 않으므로 간단히 밀리 초를 삭제해야합니다.

나는 명백한 것을 놓치고 있다고 생각하지만, 그것을 할 수있는 우아한 방법을 찾지 못했습니다 (C #).


(3 번째 시도 ...) 20 %의 답변 ( 1 , 2 , 3 )은 형식화 된 string표현 에서 밀리 초 구성 요소를 생략하거나 제거하는 방법을 설명 하므로 DateTime아마도 "잘라 내기"위해서는 편집이 필요할 수 있습니다. / "드롭"밀리 수단 "은 생산 DateTime모든 날짜 / 시간 성분을 제외한 동일한 값 TimeOfDay.TotalMilliseconds이다 0." 사람들은 물론 읽지 않고 모호성을 제거하기 위해서입니다.
— BACON

답변:


556

다음은 소수 밀리 초가있는 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
...

기술적으로 정확하기 때문에이 정보를 제공하지만 SQL Server에서 데이터를 읽는 사람들이 일부 분산 데이터 (필자의 경우 웹 기반 요청)와 비교하기 위해이 정도의 해상도는 필요하지 않습니다.
— Jeff Putz 2016 년

1
좋은. 분명히 누군가가 DateTime 클래스 에이 확장 코딩 방법을 재사용 할 수 있도록 가장 가까운 것으로 반올림하는 확장 메서드를 제공해야합니다.
— chris.w.mclean 2016 년

이것은 가능성이 거의 없지만 틱 = 0 일 때이 접근법이 중단되지 않습니까?
— adotout

@adotout, timeSpan 매개 변수가 0 인 경우 위의 Truncate 메서드는 DivideByZeroException을 발생시킵니다. 이것이 "틱이 0 일 때 접근이 중단됩니다"라는 의미입니까? timeSpan이 0 일 때 ArgumentException을 발생시키는 것이 좋습니다.
— Joe

145
var date = DateTime.Now;

date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Kind);

34
명확하고 간단합니다. 중요한 정보를 잃지 않도록 생성자 끝에 ", date.Kind"를 추가해야합니다.
— JMcDaniel

9
성능에 민감한 코드에서이 솔루션에주의하십시오. 내 앱은 System.DateTime.GetDatePart 에서 CPU 시간의 12 %를 소비했습니다 .
— 대령 패닉

3
간단하지만 최선의 답변으로 표시된 질문보다 느립니다. 이것이 병목 현상이 될 수는 없지만 약 7-8 배 더 느립니다.
— Jonas

"훨씬 느린"문장은 정확하지 않으며 런타임에 따라 차이가 50 %에서 100 % 사이입니다. net 4.7.2 : 0.35µs vs 0.62 µs 및 코어 3.1 : 0.18µs vs 0.12 µs 마이크로 초 (10 ^ -6 초)
— juwens

61

다음은 이전 답변을 기반으로 한 확장 방법으로 모든 해상도로자를 수 있습니다 ...

용법:

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);
    }
}

1
이것은 정말 유연하고 재사용 가능한 솔루션으로 지나치게 자세하지 않고 간결하고 표현력이 있습니다. 최선의 해결책으로서의 투표.
— Jaans

2
실제로 % 피연산자 주위에 괄호가 필요하지 않습니다.
— ErikE

8
.. 그러나 파렌은 제 의견으로는 명확성을 더합니다.
— 오리온 엘렌 질

28
DateTime d = DateTime.Now;
d = d.AddMilliseconds(-d.Millisecond);

70
-1 : DateTime 값에 밀리 초가 포함되지 않은 경우에만 작동합니다.
— Joe

7
이 방법을 사용하면 일부 단위 테스트가 실패했습니다. 예상 : 2010-05-05 15 : 55 : 49.000 그러나 : 2010-05-05 15 : 55 : 49.000. 나는 Joe가 밀리 초의 분수에 대해 언급 한 것으로 추측하고 있습니다.
— 세스 리노

6
직렬화에는 작동하지 않습니다 (예 : 2010-12-08T11 : 20 : 03.000099 + 15 : 00). 출력은 밀리 초를 완전히 잘라 내지 않습니다.
— joedotnot

5
이 Millisecond속성 은 0에서 999 사이 의 정수 를 제공합니다 (포함). 따라서 연산 전의 시간이 예 23:48:49.1234567를 들어 정수 123이면이고 연산 후의 시간은입니다 23:48:49.0004567. 따라서 전체 시간 (초)으로 잘리지 않았습니다.
— Jeppe Stig Nielsen

11

때로는 연도 또는 월과 같은 캘린더 기반으로 잘라 내고 싶을 때가 있습니다. 다음은 해상도를 선택할 수있는 확장 방법입니다.

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");
    }
}

9

밀리 초를 버리고 비교하는 대신 차이점을 비교하지 않는 이유는 무엇입니까?

DateTime x; DateTime y;
bool areEqual = (x-y).TotalSeconds == 0;

또는

TimeSpan precision = TimeSpan.FromSeconds(1);
bool areEqual = (x-y).Duration() < precision;

3
TotalSeconds가 두 배이므로 첫 번째 옵션이 작동하지 않습니다. 또한 밀리 초를 반환합니다.
— Jowen

1
차이를 비교한다고 잘라서 비교하는 것과 동일한 결과를 얻지 못합니다. 예를 들어 5.900과 6.100은 1 초 미만이므로 분석법과 동일하게 비교할 수 있습니다. 그러나 잘린 값 5와 6은 다릅니다. 어느 것이 적합한 지 요구 사항에 따라 다릅니다.
— Joe

7

덜 분명하지만 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);

3
두 번째 옵션 인 d.AddMilliseconds(-d.Millisecond)반드시 DateTime을 이전의 초 단위로 정확하게 이동할 필요는 없습니다. d.Ticks % TimeSpan.TicksPerMillisecond두 번째 이상으로 진드기 (0에서 9,999 사이)가 남아 있습니다.
— Technetium

5

두 번째로 반올림하려면 다음을 수행하십시오.

dateTime.AddTicks(-dateTime.Ticks % TimeSpan.TicksPerSecond)

로 교체 TicksPerMinute하여 분으로 내립니다.


코드가 성능에 민감한 경우주의하십시오

new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second)

내 앱은 System.DateTime.GetDatePart 에서 CPU 시간의 12 %를 소비했습니다 .


3

쉽게 읽을 수있는 방법은 ...

//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...

4
문자열로 변환하고 구문 분석하는 것은 성능 측면에서 끔찍한 아이디어입니다.
— Jeff Putz

2
사실 @JeffPutz, 그러나 그것은 이다 간단하지만. DB에서 삽입하고 가져온 값이 진드기를 잃는 자동 테스트에 적합합니다 (정확한 상황). 그러나이 대답은 제대로 var now = DateTime.Parse(DateTime.Now.ToString())작동 하기 때문에 훨씬 간단 할 수 있습니다 .
— Ommer Grimm

1
@GrimmTheOpiner- "... 잘 작동합니다", 그러나 대부분 보장되지는 않습니다. "현재 시간을 현재 사용자의 제어판 환경 설정에서와 같이 구성된 정밀한 시간으로 임의의 시간으로 반올림합니다." 보통은 아니지만 반드시 초입니다.
— Joe

1
단순성과 마찬가지로, 자동화 된 테스트 상황에서는 성능이 문제가되지 않습니다.
— liang

1

Diadistis 응답에 대하여. 곱하기 전에 나눗셈의 분수 부분을 제거하기 위해 Floor를 사용해야한다는 점을 제외하고는 나를 위해 일했습니다. 그래서,

d = new DateTime((d.Ticks / TimeSpan.TicksPerSecond) * TimeSpan.TicksPerSecond);

된다

d = new DateTime(Math.Floor(d.Ticks / TimeSpan.TicksPerSecond) * TimeSpan.TicksPerSecond);

두 Long 값을 나누면 Long이 발생하여 소수 부분을 제거 할 것으로 예상했지만 곱셈 후에 정확히 같은 값을 남기는 Double로 해석합니다.

간질


1

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);

1

가장 빠른 솔루션은 아니지만 간단하고 이해하기 쉽습니다.

DateTime d = DateTime.Now;
d = d.Date.AddHours(d.Hour).AddMinutes(d.Minute).AddSeconds(d.Second)

0
DateID.Text = DateTime.Today.ToShortDateString();

Use ToShortDateString() //Date 2-02-2016
Use ToShortDateString() // Time 

그리고의 사용에 의해

ToLongDateString() // its show 19 February 2016.

:피


-1. 나는 질문 string대신 DateTime에을 대신해 생산하는 것을 어떻게 잘못 해석했는지 알 수 있지만, 이것은 출력에서 ​​시간 성분을 완전히 생략한다 . ( Today그것도 재산에 대한 접근을 불필요하게 만듭니다 .)
— BACON

0

새로운 방법

String Date = DateTime.Today.ToString("dd-MMM-yyyy"); 

// 문자열 패스 매개 변수 dd-mmm-yyyy를 반환합니다.

또는 텍스트 상자에 표시

txtDate.Text = DateTime.Today.ToString("dd-MMM-yyyy");

// PageonLoad를 넣습니다


-1. 나는 질문 string대신 DateTime에을 대신해 생산하는 것을 어떻게 잘못 해석했는지 알 수 있지만, 이것은 출력에서 ​​시간 성분을 완전히 생략한다 . ( Today그것도 재산에 대한 접근을 불필요하게 만듭니다 .)
— BACON

0

필자의 경우 초와 밀리 초를 저장하지 않고 datetimePicker 도구에서 TimeSpan을 절약하려고했습니다. 여기에서 해결책이 있습니다.

먼저 datetimePicker.value를 원하는 형식 ( "HH : mm")으로 변환 한 다음 다시 TimeSpan으로 변환하십시오.

var datetime = datetimepicker1.Value.ToString("HH:mm");
TimeSpan timeSpan = Convert.ToDateTime(datetime).TimeOfDay;

더 나은 방법 (명확한 의도,에서 형식화 및 파싱을 피함 string)은 다음과 같습니다. DateTime datetime = datetimepicker1.Value; TimeSpan timeSpan = new TimeSpan(datetime.Hour, datetime.Minute, 0); 또는 값에서 작동하는 Joe의 확장 방법 을 TimeSpan사용 TimeSpan timeSpan = datetime.TimeOfDay.Truncate(TimeSpan.FromSeconds(1));하여 초를자를 수 있습니다.
— BACON

0

이것은 여기 및 비슷한 질문에 게시 된 확장 방법의 내 버전입니다. 이렇게하면 눈금 값을 읽기 쉬운 방식으로 확인하고 원래 DateTime 인스턴스의 DateTimeKind를 유지합니다. (이것은 MongoDB와 같은 데이터베이스에 저장할 때 미묘하지만 관련 부작용이 있습니다.)

진정한 목표가 DateTime을 지정된 값 (예 : Hours / Minutes / Seconds / 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;

    // /programming/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

-1

나는 대답이 꽤 늦다는 것을 알고 있지만 밀리 초를 제거하는 가장 좋은 방법은

var currentDateTime = DateTime.Now.ToString("s");

변수의 값을 인쇄하면 밀리 초없이 날짜 시간이 표시됩니다.


1
이것은 이상적이지 않습니다. DateTime이 아니라 문자열이 있습니다.
— Jeff Putz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.