C # DateTime.Now 정밀도


97

일부 단위 테스트를 수행하는 동안 DateTime.UtcNow에서 예기치 않은 동작이 발생했습니다. DateTime.Now/UtcNow를 빠르게 연속적으로 호출하면보다 정확한 밀리 초 단위를 캡처하는 대신 예상보다 긴 시간 간격 동안 동일한 값을 반환하는 것 같습니다.

정확한 시간 측정을 수행하는 데 더 적합한 Stopwatch 클래스가 있다는 것을 알고 있지만 누군가가 DateTime에서이 동작을 설명 할 수 있는지 궁금합니다. DateTime.Now에 대해 문서화 된 공식 정밀도가 있습니까 (예 : 50ms 이내의 정밀도)? 왜 DateTime.Now가 대부분의 CPU 클럭이 처리 할 수있는 것보다 덜 정확할까요? 아마도 가장 낮은 공통 분모 CPU를 위해 설계 되었을까요?

public static void Main(string[] args)
{
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    for (int i=0; i<1000; i++)
    {
        var now = DateTime.Now;
        Console.WriteLine(string.Format(
            "Ticks: {0}\tMilliseconds: {1}", now.Ticks, now.Millisecond));
    }

    stopwatch.Stop();
    Console.WriteLine("Stopwatch.ElapsedMilliseconds: {0}",
        stopwatch.ElapsedMilliseconds);

    Console.ReadLine();
}

동일한 값을 얻는 간격은 얼마입니까?
ChrisF


위의 코드를 실행했을 때 틱과 밀리 초에 대해 3 개의 고유 한 값만 얻었고 최종 스톱워치 시간은 147ms 였으므로 내 컴퓨터에서는 약 50ms로만 정확 해 보입니다 ...
Andy White

루프가 여러 번 실행되었지만 3 개의 고유 한 값만 보았습니다 ...
Andy White

여기에 오는 모든 사람을 위해 다음은 TL; DR // QueryPerformanceCounter 함수 사용 "시간 간격 측정에 사용할 수있는 고해상도 (<1us) 타임 스탬프 인 성능 카운터의 현재 값을 검색합니다." (관리 코드의 경우 System.Diagnostics.Stopwatch 클래스는 정확한 시간 기준으로 QPC를 사용합니다.) msdn.microsoft.com/en-us/library/windows/desktop/…
AnotherUser

답변:


181

왜 DateTime.Now가 대부분의 CPU 클럭이 처리 할 수있는 것보다 덜 정확할까요?

좋은 시계는 정확 하고 정확 해야합니다 . 그것들은 다릅니다. 오래된 농담처럼 멈춘 시계는 정확히 하루에 두 번 정확하고 1 분 느린 시계는 절대 정확하지 않습니다. 그러나 1 분 느린 시계는 항상 가장 가까운 분까지 정확하지만 중지 된 시계는 유용한 정밀도가 전혀 없습니다.

DateTime이 마이크로 초까지 정확할 수 없는데 마이크로 초까지 정확 해야하는 이유는 무엇 입니까? 대부분의 사람들은 마이크로 초까지 정확한 공식 시간 신호 소스가 없습니다. 따라서의 소수점 이하 여섯 자리주고 정밀도를 지난 5하는 중입니다 쓰레기가 될 것이다 거짓말 .

DateTime의 목적은 날짜와 시간나타내는 것 입니다. 고정밀 타이밍은 DateTime의 목적이 아닙니다. 아시다시피 이것이 StopWatch의 목적입니다. DateTime의 목적은 사용자에게 현재 시간을 표시하고 다음 화요일까지의 일 수를 계산하는 등의 목적으로 날짜와 시간을 나타내는 것입니다.

간단히 말해서 "몇 시지?" 그리고 "얼마나 걸렸어?" 완전히 다른 질문입니다. 한 질문에 답하기 위해 고안된 도구를 사용하여 다른 질문에 답하지 마십시오.

질문 해 주셔서 감사합니다. 이것은 좋은 블로그 기사가 될 것입니다! :-)


2
@Eric Lippert : Raymond Chen은 "정밀도"와 "정확도"의 차이에 대한 주제에 대해 예전부터 좋은 정보를 제공합니다. blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
jason

3
좋습니다. 정밀도 대 정확성에 대한 좋은 점입니다. 나는 아직도 DateTime이 정확하지 않다는 진술을 "정확하지 않아도된다"고 생각하지 않는다고 생각한다. 트랜잭션 시스템이 있고 각 레코드에 대해 날짜 시간을 표시하고 싶다면 DateTime 클래스를 사용하는 것이 직관적 인 것처럼 보이지만 .NET에는 더 정확하고 정확한 시간 구성 요소가있는 것 같습니다. 능력이 떨어졌습니다. 좀 더 읽어야 할 것 같아요 ...
Andy White

11
OK @Andy, 그런 시스템이 있다고 가정 해 봅시다. 한 시스템에서 트랜잭션이 1 월 1 일 12 : 34 : 30.23498273에 발생하는 것으로 표시합니다. 클러스터의 다른 시스템에서 트랜잭션이 1 월 1 일 12 : 34 : 30.23498456에 발생하는 것으로 표시합니다. 어떤 거래가 먼저 발생 했습니까? 두 기계 시계가 서로 마이크로 초 이내에 동기화된다는 것을 알지 못한다면 어느 것이 먼저 발생했는지 알 수 없습니다. 추가 정밀도는 오해의 소지있는 쓰레기 입니다. 내 방식이 있다면 모든 DateTime은 VBScript에서와 같이 가장 가까운 초로 반올림됩니다.
Eric Lippert

14
평균적으로 동기화되지 않은 PC는 일반적으로 몇 분이면 나오기 때문에 이것이 언급 한 문제를 해결할 수는 없습니다 . 이제 1로 반올림해도 아무것도 해결되지 않으면 왜 반올림합니까? 즉, 절대 값이 델타 시간 측정의 정확도보다 더 작은 정밀도를 가져야하는 이유에 대한 귀하의 주장을 따르지 않습니다.
Roman Starkov

3
(1) 달력 공간에서 어떤 일이 발생했을 때 (몇 초 이내) (2) 이벤트 사이의 간격 (50 밀리 초 이내)을 정확히 알아야하는 활동 로그를 생성한다고 가정 해 보겠습니다. 가장 안전한 방법은 첫 번째 작업의 타임 스탬프에 DateTime.Now를 사용한 다음 후속 작업에 대해 스톱워치를 사용하여 초기 DateTime에서 오프셋을 결정하는 것입니다. 이것이 당신이 조언 할 수있는 접근 방식입니까, 에릭?
devuxer 2013-08-06

18

DateTime의 정밀도는 실행되는 시스템에 따라 다소 다릅니다. 정밀도는 컨텍스트 전환의 속도와 관련이 있으며 약 15ms 또는 16ms입니다. (내 시스템에서는 실제로 테스트에서 약 14ms이지만 정확도가 35-40ms에 가까운 일부 랩톱을 보았습니다.)

Peter Bromberg는 이에 대해 논의하는 C #의 고정밀 코드 타이밍대한 기사를 작성 했습니다 .


2
내가 수년 동안 가지고있는 4 대의 Win7 머신은 모두 대략 1ms의 정확도를 가졌습니다. Now () sleep (1) Now ()는 테스트 할 때 항상 ~ 1ms의 datetime 변경을 가져 왔습니다.
Bengie

~ 1ms 정확도도보고 있습니다.
Timo

12

나는 정확한 Datetime.Now :)를 원하므로 이것을 요리했습니다.

public class PreciseDatetime
{
    // using DateTime.Now resulted in many many log events with the same timestamp.
    // use static variables in case there are many instances of this class in use in the same program
    // (that way they will all be in sync)
    private static readonly Stopwatch myStopwatch = new Stopwatch();
    private static System.DateTime myStopwatchStartTime;

    static PreciseDatetime()
    {
        Reset();

        try
        {
            // In case the system clock gets updated
            SystemEvents.TimeChanged += SystemEvents_TimeChanged;
        }
        catch (Exception)
        {                
        }
    }

    static void SystemEvents_TimeChanged(object sender, EventArgs e)
    {
        Reset();
    }

    // SystemEvents.TimeChanged can be slow to fire (3 secs), so allow forcing of reset
    static public void Reset()
    {
        myStopwatchStartTime = System.DateTime.Now;
        myStopwatch.Restart();
    }

    public System.DateTime Now { get { return myStopwatchStartTime.Add(myStopwatch.Elapsed); } }
}

2
이 솔루션이 마음에 들지만 확실하지 않아서 내 질문을했습니다 ( stackoverflow.com/q/18257987/270348 ). Servy의 댓글 / 답변에 따라 스톱워치를 재설정해서는 안됩니다.
RobSiklos 2013-08-15

1
아마도 당신의 맥락이 아닐 수도 있지만 재설정은 내 맥락에서 의미가 있습니다. 나는 타이밍이 실제로 시작되기 전에 완료되었는지 확인합니다.
Jimmy

구독이 필요하지 않으며 스톱워치를 재설정 할 필요가 없습니다. 이 코드를 ~ 10ms마다 실행할 필요는 없으며 CPU를 소모합니다. 그리고이 코드는 스레드로부터 안전하지 않습니다. myStopwatchStartTime = DateTime.UtcNow를 초기화하면됩니다. 한 번, 정적 생성자에서.
VeganHunter

1
@VeganHunter 귀하의 의견을 올바르게 이해하고 있는지 확실하지 않지만 TimeChanged가 ~ 10ms마다 호출된다고 생각하는 것 같습니다. 그렇지 않습니다.
Jimmy

@ 지미, 당신 말이 맞아요. 내 잘못이야, 나는 코드를 오해했다. SystemEvents.TimeChanged 이벤트는 사용자가 시스템 시간을 변경하는 경우에만 호출됩니다. 드문 이벤트입니다.
VeganHunter

6

에서 MSDN 당신은 찾을거야 DateTime.Now대략 모든 NT 운영 체제에서 10 밀리 초 해상도를.

실제 정밀도는 하드웨어에 따라 다릅니다. 를 사용하여 더 나은 정밀도를 얻을 수 있습니다 QueryPerformanceCounter.


5

실제로 .NET 소스를 확인하는 것보다 가치가있는 것에 대해 Eric Lippert는 이 SO 질문에 대해 DateTime이 약 30ms까지만 정확하다는 의견을 제공 했습니다 . 나노초가 정확하지 않은 이유는 "그럴 필요가 없다"는 것입니다.


4
그리고 더 나쁠 수 있습니다. VBScript에서 Now () 함수는 반환 된 결과를 가장 가까운 초로 반올림하고, 반환 된 값이 마이크로 초까지 정확할 수있는 충분한 정밀도를 가지고 있다는 사실을 설명합니다. C #에서 구조는 DateTime이라고합니다. 생명 보험이 만료되는시기 또는 마지막 재부팅 이후 경과 된 시간과 같은 일반적인 실제 비 과학적 도메인의 날짜와 시간을 나타 내기위한 것입니다. 고정밀 서브 초 타이밍을위한 것이 아닙니다.
Eric Lippert

3

MSDN 문서에서 :

이 속성의 해상도는 시스템 타이머에 따라 다릅니다.

그들은 또한 Windows NT 3.5 이상에서 대략적인 해상도가 10ms라고 주장합니다. :)


1

이 속성의 해상도는 기본 운영 체제에 따라 달라지는 시스템 타이머에 따라 다릅니다. 0.5에서 15 밀리 초 사이 인 경향이 있습니다 .

결과적으로 루프에서와 같이 짧은 시간 간격으로 Now 속성을 반복적으로 호출하면 동일한 값이 반환 될 수 있습니다.

MSDN 링크

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.