Funkcja, która tworzy znacznik czasu w języku C #


101

Zastanawiałem się, czy istnieje sposób na utworzenie znacznika czasu w języku c # z datetime? Potrzebuję wartości precyzji milisekundy, która działa również w Compact Framework (mówiąc, że ponieważ DateTime.ToBinary () nie istnieje w CF).

Mój problem polega na tym, że chcę przechowywać tę wartość w sposób agnostyczny bazy danych, aby móc ją później sortować i dowiedzieć się, która wartość jest większa od innej itp.


2
Przyjęta odpowiedź tutaj daje fajne rozwiązanie, ale jeśli chcesz mieć prawdziwy znacznik czasu, sprawdź to
pytanie

Odpowiedzi:


206

Zawsze używam czegoś takiego:

public static String GetTimestamp(this DateTime value)
{
    return value.ToString("yyyyMMddHHmmssfff");
}

To da ci ciąg taki jak 200905211035131468, ponieważ ciąg przechodzi od bitów najwyższego rzędu znacznika czasu do najniższego rzędu prostego sortowania ciągów w zapytaniach SQL może być używane do sortowania według daty, jeśli przechowujesz wartości w bazie danych


5
Dlaczego masz 21 miesięcy, a tylko 12? :)
PaulB

2
W tym miejscu token oznaczający rok powinien być zapisany małymi literami: return value.ToString ("rrrrMMddHHmmssffff");
Don Cote

1
@RobV Pytanie wymaga milisekundowej precyzji, więc na końcu potrzebujesz 3 'f. Twoje 4 stopy zapewniają dokładność 100 mikrosend.
Evgeniy Berezovsky

2
Należy pamiętać, że Compact Framework nie przenosi milisekund. Zawsze będą równe 0. Musisz zmodyfikować kod i dodać coś takiego: int tick = Environment.TickCount% 1000; int ms = (tick> = MOffset)? (tick - MOffset): (1000 - (MOffset - tick)); ms = Math.Min (999; Math.Max ​​(0, ms));
Redwolf

44

Uważam, że możesz utworzyć sygnaturę daty w stylu uniksowym z dokładnością do sekundy, korzystając z następującego

//Find unix timestamp (seconds since 01/01/1970)
long ticks = DateTime.UtcNow.Ticks - DateTime.Parse("01/01/1970 00:00:00").Ticks;
ticks /= 10000000; //Convert windows ticks to seconds
timestamp = ticks.ToString();

Dostosowanie mianownika pozwala wybrać poziom precyzji


19

Możesz użyć właściwości DateTime.Ticks, która jest długa i uniwersalna, którą można przechowywać, zawsze rośnie i jest używana również w zwartej strukturze. Tylko upewnij się, że Twój kod nie jest używany po 31 grudnia 9999;)


Kiedy mówisz „zawsze rosnąco” - nie ma gwarancji, że dwa wywołania DateTime.UtcNow.Ticks podadzą różne wartości, prawda? Innymi słowy, nadal potrzebujesz ostrożności, zanim użyjesz go jako unikalnego znacznika czasu.
Jon Skeet

9
@Konstantinos: nie możesz uniknąć duplikatów, jeśli używasz znaczników czasu. Sygnatury czasowe nie są używane do unikatowych kluczy, ale do oznaczania czasu. Powiedziałeś, że potrzebujesz milisekundowej precyzji, a tyknięcia mają dokładność 100 ns. Chodzi o to, że będziesz mieć duplikaty. Jeśli nie chcesz, potrzebujesz unikalnej sekwencji w DB, która niestety nie jest agnostyczna db.
Frans Bouma

3
„to prawdziwa liczba kleszczy, która rośnie w czasie”. Ale zegar systemowy może się cofnąć - np. Pod koniec czasu letniego, jeśli używasz czasu lokalnego lub ponieważ zegar systemowy został wyregulowany.
Joe

1
@Frans: absolutnie. Zrobiłem komentarz tylko dlatego, że ludzie powinni pomyśleć o konsekwencjach rozwiązania, które wybrali. Na przykład użyłbym czasu UTC zamiast czasu lokalnego, aby przynajmniej wyeliminować problemy związane z czasem letnim.
Joe

1
@konstantinos: hmm ... dokumentacja twierdzi, że ma precyzję 100 ns, więc rzeczywiście dziwne, że nie ma takiej precyzji, jak udokumentowano. Być może rzeczywiście jest to kompaktowy framework, nie jest to framework bez błędów
Frans Bouma


4

kiedy potrzebujesz znacznika czasu w sekundach, możesz użyć:

var timestamp = (int)(DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalSeconds;

2

Jeśli chcesz, aby znaczniki czasu odpowiadały rzeczywistym czasom, ALE aby były również unikalne (dla danej instancji aplikacji), możesz użyć następującego kodu:

public class HiResDateTime
{
   private static long lastTimeStamp = DateTime.UtcNow.Ticks;
   public static long UtcNowTicks
   {
       get
       {
           long orig, newval;
           do
           {
               orig = lastTimeStamp;
               long now = DateTime.UtcNow.Ticks;
               newval = Math.Max(now, orig + 1);
           } while (Interlocked.CompareExchange
                        (ref lastTimeStamp, newval, orig) != orig);

           return newval;
       }
   }
}
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.