Uzyskaj czas w milisekundach przy użyciu języka C #

131

Robię program, w którym potrzebuję mierzyć czas w milisekundach. Mam na myśli liczbę, która nigdy nie jest sobie równa i jest zawsze o 1000 liczb większa niż przed sekundą. Próbowałem przekonwertować DateTime.Nowna a TimeSpani uzyskać TotalMillisecondsz tego ... ale słyszałem, że nie jest to idealnie dokładne.

Czy jest na to łatwiejszy sposób?

Jednostka
źródło
Czy oczekujesz, że jakiekolwiek dwa wezwania będą zawsze prowadzić do wzrostu wartości? Ogólnie, wywołania bliżej niż minimalny interwał, na który pozwala rozdzielczość timera, dają tę samą wartość. Musisz dodać własny remis w postaci fałszywego precyzyjnego serializatora.
Steven Sudit
16
„Liczba, która nigdy nie jest sobie równa”. To brzmi ... skomplikowanie. ;)
Mizipzor
1
NaN faktycznie spełniłby ten wymóg. Mimo że nie jest liczbą, jest typem liczbowym i nie jest sobie równa.
Yay295

Odpowiedzi:

78

Skorzystaj z Stopwatchklasy.

Zawiera zestaw metod i właściwości, których można użyć do dokładnego pomiaru czasu, który upłynął.

Jest kilka dobrych informacji na temat implementacji tutaj:

Testy wydajności: precyzyjne pomiary czasu pracy z diagnostyką systemową. Stoper

RedFilter
źródło
8
stoper jest częścią Diagnostyki. Czy powinien być używany w prawdziwym kodzie?
Andrey,
Zwykle jest to dokładne tylko do najbliższych 15 ms.
Steven Sudit
11
ile to kosztuje? może powinniśmy stoper stoper :)
jb.
3
@Steven, to zależy od systemu operacyjnego i używanego sprzętu. Jeśli jest dostępny, używany jest licznik czasu o wysokiej rozdzielczości, co ma miejsce w przypadku wszystkich obecnych wersji Windows x86 opartych na komputerach stacjonarnych i serwerach, które znam. Sprawdź właściwości Frequency i IsHighResolution, aby uzyskać więcej informacji. Na poziomie systemu operacyjnego QueryPerformanceCounter i QueryPerformanceFrequency są interfejsami API niskiego poziomu, które wspierają tę funkcjonalność.
Chris Taylor,
320
long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;

Oto jak różne metody konwersji Uniksa są implementowane w DateTimeOffsetklasie (.NET Framework 4.6+, .NET Standard 1.3+):

long milliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Evan Mulawski
źródło
65
Tytuł to „uzyskaj czas w milisekundach”. Ta odpowiedź jest pomocna.
Aerospace
33
Tak, dla tych z nas, którzy szukają odpowiedzi na zadane pytanie, było to bardzo pomocne, dziękuję.
user430788
1
Jeśli potrzebujesz liczb dziesiętnych (nawet jeśli DateTime.Nownie są one często „aktualizowane”), oczywiście użyj decimal milliseconds = DateTime.Now.Ticks / (decimal)TimeSpan.TicksPerMillisecond;zamiast nich.
Jeppe Stig Nielsen
1
Jest to o wiele bardziej przydatne niż wybrana odpowiedź dla wyników wyszukiwania, a nawet dla tego, co wyciągnąłem z pierwotnego pytania.
bwoogie
1
Ta odpowiedź uratowała mi życie. Mam podobny kod, ale nie działa. Nie mogłem zrozumieć, dlaczego. Wtedy zobaczyłem longtyp danych przed milisekundami. Używanie z intpewnością się przepełni.
FisNaN
13

DateTime.TicksNieruchomość dostaje liczbę kleszczy, które reprezentują datę i godzinę.

10000 tyknięć to milisekunda (10000000 tyknięć na sekundę).

Itay Karo
źródło
4
Ale rozdzielczość kleszczy jest znacznie mniejsza niż
1/10 000 s
2
@codymanix - z MSDN:A single tick represents one hundred nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond.
Itay Karo,
5
Jasne, że tak, ale system operacyjny nie ma takiej rozdzielczości.
codymanix
6
@codymanix jest poprawne. Analogicznie, angstrem to jednostka długości; dziesięć miliardów angstremów tworzy jeden metr. Mógłbyś napisać funkcję, która podaje Twój wzrost jako 64-bitową liczbę całkowitą w angstremach, ale jeśli wszystko, co masz, to metrestick z dokładnością do centymetra, to fakt, że funkcja reprezentuje precyzję poniżej nanometra, jest całkowicie nieistotny. Mniej znaczące cyfry będą śmieciami.
Eric Lippert,
4
@RedFilter: Gdybyś rzeczywiście znał swój wiek z dokładnością do najbliższej milisekundy, mógłbyś powiedzieć coś w rodzaju: „Kiedy ponownie mrugnę, mój wiek wyniesie x milisekund”. Głębszym problemem nie jest komunikacja, ale pomiar: Twoje narodziny prawdopodobnie nie zostaną poznane nawet z dokładnością do sekundy.
Steven Sudit,
11

Używam następującej klasy. Znalazłem go kiedyś w internecie, postulowałem, że jest najlepszy TERAZ () .

/// <summary>Class to get current timestamp with enough precision</summary>
static class CurrentMillis
{
    private static readonly DateTime Jan1St1970 = new DateTime (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    /// <summary>Get extra long current timestamp</summary>
    public static long Millis { get { return (long)((DateTime.UtcNow - Jan1St1970).TotalMilliseconds); } }
}

Źródło nieznane.

schmijos
źródło
5
FWIW, cały cel tego powszechnie używanego fragmentu kodu, polega na utworzeniu znacznika czasu zgodnego ze standardem sygnatury czasowej Uniksa. W tym celu jest to niezbędne. Jeśli ktoś chce tylko mierzyć czas, jest to niepotrzebnie kosztowne.
ToolmakerSteve
8

Możesz wypróbować QueryPerformanceCountermetodę natywną. Więcej informacji można znaleźć pod adresem http://www.pinvoke.net/default.aspx/kernel32/QueryPerformanceCounter.html . To jest to, czego Stopwatchużywa klasa.

Zobacz jak uzyskać znacznik czasu precyzji taktu w .NET / C #? po więcej informacji.

Stopwatch.GetTimestamp() daje dostęp do tej metody:

public static long GetTimestamp() {
     if(IsHighResolution) {
         long timestamp = 0;
         SafeNativeMethods.QueryPerformanceCounter(out timestamp);
         return timestamp;
     }
     else {
         return DateTime.UtcNow.Ticks;
     }
 }
Pieter van Ginkel
źródło
1
AFAIK StopWatch korzysta wewnętrznie z QueryPerformanceCounter, jeśli jest dostępny
codymanix
Tak, wewnętrzna implementacja Stopwatch.GetTimestamp()faktycznie zapewnia dostęp do tej metody.
Pieter van Ginkel,
5

Użyłem DateTime.Now.TimeOfDay.TotalMilliseconds (na bieżący dzień), mam nadzieję, że to również ci pomoże.

Sarvan
źródło
1
który nie zwróci rosnących wartości (jak wymagany był oryginalny plakat), ponieważ TimeOfDay jest resetowany do zera codziennie o północy. Poza tym miałby te same potencjalne problemy, o których wspomniał plakat, używając tylko DateTime, a teraz uzyskuje się z tego całkowite milisekundy.
Jim O'Neil,
3
Jim O'Neil Zgadzam się z tobą, dlatego wspomniałem w moim poście "(na bieżący dzień)" ... Przy okazji, moje rozwiązanie zadziałało na mój problem, ponieważ mój problem nie jest związany z datą, po prostu musiałem uzyskać część milisekund do wykorzystania jako licznik, więc opublikowałem ją tutaj. Jestem tu nowy, więc jeśli zamieściłem go w złym miejscu to przepraszam :)
Sarvan
2

Użyj System.DateTime.Now.ToUniversalTime(). To umieszcza twój odczyt w znanym formacie milisekund opartym na referencji, który całkowicie eliminuje zmianę dnia itp.

John Tobler
źródło
Dobrze wiedzieć, ale nie dotyczy zadawanego pytania, które dotyczy synchronizacji (pomiaru upływu czasu), a nie dokładnego przekazywania czasu.
ToolmakerSteve