Jak konwertować czas epoki w C #?

377

Jak konwertować czas epoki uniksowej na czas rzeczywisty w języku C #? (Początek epoki 1/1/1970)

hsatterwhite
źródło
1
O ile mi czegoś nie brakuje, „epoka” jest po prostu punktem początkowym określonego schematu pomiaru czasu. Przykłady obejmują 1/1/0001, 1/1/1970 i 1/1/2000. To bardziej atrybut schematu niż samego schematu (np. Julian).
Bob Kaufman
8
Czas od epoki to liczba sekund od 1 stycznia 1970 roku UTC.
Taylor Leese
13
@Taylor To epoka czasu uniksowego i prawdopodobnie ma rację, ale to nie jedyna ważna epoka. Użytkownicy czasu uniksowego nie powinni się mylić w tym punkcie.
Joel Coehoorn
Dup, z innymi odpowiedziami: stackoverflow.com/q/3354893/712526
jpaugh

Odpowiedzi:

563

Zakładam, że masz na myśli czas uniksowy , który jest zdefiniowany jako liczba sekund od północy (UTC) 1 stycznia 1970 r.

public static DateTime FromUnixTime(long unixTime)
{
    return epoch.AddSeconds(unixTime);
}
private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
Łukasz
źródło
74
Aby to działało poprawnie, musiałem zmienić .AddSeconds na .AddMilliseconds. Będziesz musiał wiedzieć, czy twój numer pochodzi z Sekundy czy Milisekund, aby uzyskać poprawny wynik. Na przykład następująca data: 1406310305188 (25 lipca 2014 r.). epochconverter.com pozwoli ci również sprawdzić wyniki konwersji.
jrandomuser
5
Powinieneś albo zmienić typ parametru na double (ponieważ AddSeconds akceptuje double, a zatem zostanie zmniejszony do double) lub dodaj zastrzeżenie do opisu metody, że zachowane zostaną tylko 53 z 64 bitów precyzji w argumencie.
tomosius
6
@jrandomuser: Czas epoki uniksowej jest tradycyjnie reprezentowany jako sekundy od Epoki. Od tego czasu powszechne jest używanie milisekund od Epoki (na przykład JavaScript), ale klasyczna definicja to sekundy. Podsumowując, po prostu wiedz, jaka jest twoja wartość wejściowa (sekundy, milisekundy, tiki, cokolwiek) i użyj właściwej AddXYZmetody.
TJ Crowder,
Najpierw spróbuj z AddMilliseconds, a jeśli nadal jest rok 1970, wykonaj AddSeconds. W ten sposób będzie działał cały czas, bez martwienia się o milisekundy lub sekundy. Dodatkowo możesz zapobiec przepełnieniu. Przekazywanie dużej liczby do AddSeconds spowoduje awarię kodu
Tono Nam
213

Najnowszą wersję .NET (v4.6) po prostu dodał wbudowane wsparcie dla systemu UNIX konwersji czasowych. Obejmuje to zarówno do, jak i od czasu uniksowego reprezentowanego przez sekundy lub milisekundy.

  • Czas uniksowy w sekundach na DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset do czasu uniksowego w sekundach:

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • Czas uniksowy w milisekundach do DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset do czasu uniksowego w milisekundach:

long unixTimeStampInMilliseconds= dateTimeOffset.ToUnixTimeMilliseconds();

Uwaga: Te metody są konwertowane na i z DateTimeOffset. Aby uzyskać DateTimereprezentację, wystarczy użyć DateTimeOffset.DateTimewłaściwości:

DateTime dateTime = dateTimeOffset.UtcDateTime;
i3arnon
źródło
1
Dostaję 'DateTimeOffset' does not contain a definition for 'FromUnixTimeSeconds'Jak mógłbym rozwiązać ten problem?
Happy Bird
@HappyBird Czy korzystasz z platformy .NET 4.6 lub nowszej?
i3arnon
To samo - 4.7.2 i nie ma metody FromUnixTimeMilliseconds dla DateTimeOffset ...
Mikhail_Sam
Mam to. Nie muszę tworzyć nowego obiektu. To metoda statyczna.
Mikhail_Sam
Na pierwszy rzut oka stwierdziłem, że wartości domyślne są nieco mylące. Bc 1000 to współczynnik przeliczany z milisekund na sekundy.
BluE
169

Z całym podziękowaniem dla LukeH, opracowałem kilka metod rozszerzenia dla łatwego użycia:

public static DateTime FromUnixTime(this long unixTime)
{
    var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    return epoch.AddSeconds(unixTime);
}

public static long ToUnixTime(this DateTime date)
{
    var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    return Convert.ToInt64((date - epoch).TotalSeconds);
}

Należy zwrócić uwagę na komentarz poniżej z CodesInChaos że powyższe FromUnixTimeZwraca DateTimez Kindod Utc, co jest w porządku, ale wyżej ToUnixTimejest o wiele bardziej podejrzany, który nie bierze pod uwagę, jakie DateTimedana datejest. Aby umożliwić date„s Kindjest albo Utcalbo Local, użyj ToUniversalTime:

public static long ToUnixTime(this DateTime date)
{
    var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    return Convert.ToInt64((date.ToUniversalTime() - epoch).TotalSeconds);
}

ToUniversalTimeprzekonwertuje Local(lub Unspecified) DateTimena Utc.

jeśli nie chcesz tworzyć instancji DateTime epoki podczas przenoszenia z DateTime do epoki, możesz również:

public static long ToUnixTime(this DateTime date)
{
    return (date.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
}
Ben Cull
źródło
6
ToUnixTimedziała poprawnie tylko wtedy, gdy data jest w Utc. Dodaj czek lub przekonwertuj go. (Osobiście wolę czek)
CodesInChaos
2
Właśnie spędziłem ostatnią godzinę zastanawiając się, dlaczego to nie działa. Musisz pracować w milliseconds nie sekund !!!
KristianB,
7
@KristianB: „Czas uniksowy” to tradycyjnie sekundy, a nie milisekundy od Epoki, chociaż obecnie staram się sprawdzić, jakiej definicji używa ktoś. Sekundy były wystarczająco dobre i dawały nam rozsądny zasięg po obu stronach Epoki w wartościach 32-bitowych ze znakiem. (I dlatego tuż po 03:14 19 stycznia 2038 GMT może być dla niektórych zły moment ...) Używanie milisekund jest bardziej nowoczesną praktyką, ponieważ rutynowo jesteśmy w stanie wyrzucać około 64-bitowych wartości (obie integralne i podwójnej precyzji IEEE-754) ...
TJ Crowder
5
Dzięki za kod. Tylko niewielka rekomendacja podczas tworzenia podstawy Epoki: pamiętaj, aby jawnie ustawić wartość Millisecond na 0. tzn. Var epoch = new DateTime (1970, 1, 1, 0 / * h * /, 0 / * m * /, 0 / * s * /, 0 / * ms * /, DateTimeKind.Utc); Jeśli nie ustawisz go wyraźnie, wartość milisekundy wydaje się wynosić 1. To spowodowało pewne niespójności w moich testach.
ctrlplusb
1
Powinieneś użyć AddMillisecondsi powinieneś użyć Double NOT Float. W przeciwnym razie skończy się zły czas.
Axel
25

Naprawdę chcesz dodać milisekundy (milisekundy), a nie sekundy. Dodanie sekund da wyjątek poza zakresem.

Darya
źródło
Dlaczego? epochconverter.com Mówi, że dodajesz liczbę sekund od 1/1/970, a nie ms.
Jamie R Rytlewski
Jeśli wybierasz się z ms, to oczywiście chcesz, AddMillisa jeśli zaczynasz od sekund, to oczywiście chcesz AddSeconds.
But
Miałem ten sam problem, z którego korzystałem przez kilka sekund. Czas uniksowy, który próbowałem przekonwertować, trwał w milisekundach. Myślałem, że to w kilka sekund. Wydaje mi się, że jakiś czas uniksowy jest mierzony w milisekundach.
DoodleKana,
Czas uniksowy jest zwykle wyrażany w sekundach, ale 0,001 jest prawidłową liczbą sekund (= 1 ms). W razie wątpliwości użyj maksymalnej możliwej precyzji.
Scott,
9

Jeśli chcesz uzyskać lepszą wydajność, możesz użyć tej wersji.

public const long UnixEpochTicks = 621355968000000000;
public const long TicksPerMillisecond = 10000;
public const long TicksPerSecond = TicksPerMillisecond * 1000;

//[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static DateTime FromUnixTimestamp(this long unixTime)
{
    return new DateTime(UnixEpochTicks + unixTime * TicksPerSecond);
}

Z szybkiego testu porównawczego (BenchmarkDotNet) pod net471 otrzymuję ten numer:

        Method |     Mean |     Error |    StdDev | Scaled |
-------------- |---------:|----------:|----------:|-------:|
         LukeH | 5.897 ns | 0.0897 ns | 0.0795 ns |   1.00 |
      MyCustom | 3.176 ns | 0.0573 ns | 0.0536 ns |   0.54 |

2x szybciej w porównaniu z wersją LukeH (jeśli wydajność ma znaczenie)

Jest to podobne do wewnętrznego działania DateTime.

Jiri Sykora
źródło
9

Użyj metody DateTimeOffset.ToUnixTimeMilliseconds () Zwraca liczbę milisekund, które upłynęły od 1970-01-01T00: 00: 00.000Z.

Jest to obsługiwane tylko w Framework 4.6 lub nowszym

var EPOCH = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

Jest tu dobrze udokumentowane DateTimeOffset.ToUnixTimeMilliseconds

Innym wyjściem jest skorzystanie z poniższych

long EPOCH = DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1,0,0,0,0).Ticks;

Aby uzyskać EPOCH w kilka sekund, możesz użyć tylko tego

 var Epoch = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;

i przekonwertować Epochdo DateTimez następującym sposobem

private DateTime Epoch2UTCNow(int epoch) 
{
    return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(epoch); 
}
Vinod Srivastav
źródło
DateTime.Ticks - każdy tik to „sto nanosekund”, co czyni go dodatkową „rzeczą” do zapamiętania. Jeśli pominiesz oba .Ticks, odzyskasz ładną instancję TimeSpan z odejmowania DateTime.
user2864740,
8
// convert datetime to unix epoch seconds
public static long ToUnixTime(DateTime date)
{
    var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    return Convert.ToInt64((date.ToUniversalTime() - epoch).TotalSeconds);
}

Należy użyć ToUniversalTime () dla obiektu DateTime.

Green Su
źródło
5

Używam następujących metod rozszerzenia do konwersji epoki

public static int GetEpochSeconds(this DateTime date)
    {
        TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
        return (int)t.TotalSeconds;
    }

public static DateTime FromEpochSeconds(this DateTime date, long EpochSeconds)
    {
        var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        return epoch.AddSeconds(EpochSeconds);

    }
faisal00813
źródło
2

Aby nie martwić się o użycie milisekund lub sekund, po prostu:

    public static DateTime _ToDateTime(this long unixEpochTime)
    {
        DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        var date = epoch.AddMilliseconds(unixEpochTime);

        if (date.Year > 1972)
            return date;

        return epoch.AddSeconds(unixEpochTime);
    }

Jeśli czas epoki jest w sekundach, nie można w żaden sposób przekroczyć roku 1972, dodając milisekundy.

Tono Nam
źródło
1

Jeśli nie korzystasz z wersji 4.6, może to pomóc Source: System.IdentityModel.Tokens

    /// <summary>
    /// DateTime as UTV for UnixEpoch
    /// </summary>
    public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

    /// <summary>
    /// Per JWT spec:
    /// Gets the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the desired date/time.
    /// </summary>
    /// <param name="datetime">The DateTime to convert to seconds.</param>
    /// <remarks>if dateTimeUtc less than UnixEpoch, return 0</remarks>
    /// <returns>the number of seconds since Unix Epoch.</returns>
    public static long GetIntDate(DateTime datetime)
    {
        DateTime dateTimeUtc = datetime;
        if (datetime.Kind != DateTimeKind.Utc)
        {
            dateTimeUtc = datetime.ToUniversalTime();
        }

        if (dateTimeUtc.ToUniversalTime() <= UnixEpoch)
        {
            return 0;
        }

        return (long)(dateTimeUtc - UnixEpoch).TotalSeconds;
    }    
Siva Kandaraj
źródło
Dzięki na przykład z JWT. Nawiasem mówiąc, aby go użyć, po prostu użyj: using Microsoft.IdentityModel.Tokens; ... EpochTime.GetIntDate(dateTime);
fluid
0

Jeśli chcesz przekonwertować strukturę czasową (sekundy, mikrosekundy) zawierającą UNIX timena DateTimebez utraty precyzji, oto jak to zrobić :

DateTime _epochTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private DateTime UnixTimeToDateTime(Timeval unixTime)
{
    return _epochTime.AddTicks(
        unixTime.Seconds * TimeSpan.TicksPerSecond +
        unixTime.Microseconds * TimeSpan.TicksPerMillisecond/1000);
}
i3arnon
źródło
0

Od wersji .Net 4.6 i nowszych należy używać funkcji DateTimeOffset.Now.ToUnixTimeSeconds ()

Saikat Chakraborty
źródło
-4

Oto moje rozwiązanie:

public long GetTime()
{
    DateTime dtCurTime = DateTime.Now.ToUniversalTime();

    DateTime dtEpochStartTime = Convert.ToDateTime("1/1/1970 0:00:00 AM");

    TimeSpan ts = dtCurTime.Subtract(dtEpochStartTime);

    double epochtime;

    epochtime = ((((((ts.Days * 24) + ts.Hours) * 60) + ts.Minutes) * 60) + ts.Seconds);   

    return Convert.ToInt64(epochtime);
}
sandeep
źródło
7
czy to konto dotyczy lat przestępnych i sekund przestępnych itp.?
Jodrell,
1
Aby rozwinąć poprzedni komentarz, oto krótkie wideo wyjaśniające, dlaczego czas jest skomplikowany i dlaczego nie powinieneś próbować robić tego sam: youtube.com/watch?v=-5wpm-gesOY
vmrob