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