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?


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


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

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


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.


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

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.


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.


Dobrze wiedzieć, ale nie dotyczy zadawanego pytania, które dotyczy synchronizacji (pomiaru upływu czasu), a nie dokładnego przekazywania czasu.
ToolmakerSteve
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.