Jak mogę przekonwertować DateTime na liczbę sekund od 1970 roku?

119

Próbuję przekonwertować zmienną DateTime języka C # na czas uniksowy, tj. Liczbę sekund od 1 stycznia 1970 r. Wygląda na to, że DateTime jest faktycznie zaimplementowany jako liczba „taktów” od 1 stycznia 0001.

Obecnie myślę o odjęciu 1 stycznia 1970 od daty i godziny w następujący sposób:

TimeSpan span= DateTime.Now.Subtract(new DateTime(1970,1,1,0,0,0));
return span.TotalSeconds;

Czy jest lepszy sposób?

Slider345
źródło
1
Możliwy duplikat Jak przekonwertować czas epoki w C #?
jpaugh

Odpowiedzi:

195

W zasadzie to wszystko. Oto metody, których używam do konwersji do i z czasu uniksowego:

public static DateTime ConvertFromUnixTimestamp(double timestamp)
{
    DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
    return origin.AddSeconds(timestamp);
}

public static double ConvertToUnixTimestamp(DateTime date)
{
    DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
    TimeSpan diff = date.ToUniversalTime() - origin;
    return Math.Floor(diff.TotalSeconds);
}

Aktualizacja: Począwszy od .Net Core 2.1 i .Net Standard 2.1, data i godzina równa uniksowej epoce można uzyskać ze statycznego DateTime.UnixEpoch.

Dave Swersky
źródło
1
Warto zauważyć, że jeśli chcesz konwertować na milisekundy, aby uzyskać dokładniejsze znaczniki czasu lub zgodność obiektów JavaScript Date (), musisz użyć long zamiast int dla typu znacznika czasu.
Soviut,
3
Nie działa dla mnie. Ta odpowiedź
załatwiła sprawę
@Jonny - ToUniversalTime () konwertuje na UTC, więc uwzględnia UTC.
Dave Swersky,
4
DateTime origin = new DateTime (1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); Ciekawe, że nikt tego nie zasugerował. Bardzo często będziesz mieć milisekundy reprezentujące czas Utc. A jeśli nie t specify this explicitly and somewhere later in code youbędziesz mieć ToUniversalTime (), wtedy skończy się zły czas w Utc, ponieważ domyślnie DateTime NIE jest Utc.
ostry
52

Jeśli reszta twojego systemu jest w porządku z DateTimeOffset zamiast DateTime, istnieje naprawdę wygodna funkcja:

long unixSeconds = DateTimeOffset.Now.ToUnixTimeSeconds();
codeMonkey
źródło
7
Jest to bardziej przejrzysty sposób, ale jest dostępny tylko we frameworku 4.6 msdn.microsoft.com/en-us/library/ ...
Oscar Fraxedas
1
Miły. Oczywiście, aby przejść z unixa do DateTimeOffset, możesz użyć var time = DateTimeOffset.FromUnixTimeSeconds(5000); MS Doc
Jordan,
22

Jedyne, co widzę, to to, że miało to być od północy 1 stycznia 1970 UTC

TimeSpan span= DateTime.Now.Subtract(new DateTime(1970,1,1,0,0,0, DateTimeKind.Utc));
return span.TotalSeconds;
CaffGeek
źródło
7
Czy powinien to być DateTime.UtcNow?
oferei
14

Prawdopodobnie chcesz użyć DateTime.UtcNow, aby uniknąć problemu ze strefą czasową

TimeSpan span= DateTime.UtcNow.Subtract(new DateTime(1970,1,1,0,0,0)); 
David
źródło
Jedynym sposobem uniknięcia problemów ze strefą czasową jest 1) pozostawanie w błogiej ignorancji i obsługa tylko jednej strefy czasowej lub 2) obsługa stref czasowych (przynajmniej) wszędzie tam, gdzie łączysz się z innym systemem lub użytkownikiem końcowym. W szczególności wewnętrzne używanie UTC wszędzie jest tylko częścią bitwy. W pierwszym scenariuszu dodanie czasów UTC faktycznie pogarsza problem, dopóki nie będziesz gotowy do wykonania wszystkich (2), ponieważ przechodzisz od obsługi jednej strefy czasowej do obsługi tylko UTC.
jpaugh
1

Takie podejście będzie dobre, jeśli dana data jest w czasie UTC lub reprezentuje czas lokalny w obszarze, w którym nigdy nie obserwowano czasu letniego. Procedury różnicowe DateTime nie biorą pod uwagę czasu letniego, w związku z czym będą traktować północ 1 czerwca jako wielokrotność 24 godzin po północy 1 stycznia. Nie znam niczego w systemie Windows, który zgłasza historyczne reguły czasu letniego dla bieżącego locale, więc nie sądzę, aby można było poprawnie obsłużyć czas przed ostatnią zmianą reguły czasu letniego.

superkat
źródło
0

Możesz utworzyć startTime i endTime DateTime, a następnie wykonaj endTime.Subtract (startTime). Następnie podaj wartość span.Seconds.

Myślę, że to powinno działać.

Alec Sanger
źródło
0

Używam roku 2000 zamiast czasu epoki w moim rachunku różniczkowym. Praca z mniejszymi liczbami jest łatwa do przechowywania i transportu oraz jest przyjazna dla formatu JSON.

Rok 2000 był drugim 946684800 epoki.

Rok 2000 był drugim 63082281600 od 1 stycznia 0001.

DateTime.UtcNow Ticks zaczyna się 1 stycznia 0001

Sekundy od 2000 roku :

DateTime.UtcNow.Ticks/10000000-63082281600

Sekundy od czasu uniksowego:

DateTime.UtcNow.Ticks/10000000-946684800

Na przykład rok 2020 to:

var year2020 = (new DateTime ()). AddYears (2019) .Ticks; // Ponieważ DateTime zaczyna się już w roku 1

637134336000000000 Kleszcze od 1 stycznia 0001

63713433600 Sekundy od 1 stycznia 0001

1577836800 sekund od czasu epoki

631152000 sekund od 2000 roku

Bibliografia:

Konwerter czasu epoki: https://www.epochconverter.com

Konwerter roku 1: https://www.epochconverter.com/seconds-days-since-y0

profimedica
źródło