Jak mogę przekonwertować uniksowy znacznik czasu na DateTime i odwrotnie?

754

Jest ten przykładowy kod, ale potem zaczyna mówić o problemach milisekund / nanosekund.

To samo pytanie dotyczy MSDN, Seconds od epoki Uniksa w C # .

Oto co mam do tej pory:

public Double CreatedEpoch
{
  get
  {
    DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime();
    TimeSpan span = (this.Created.ToLocalTime() - epoch);
    return span.TotalSeconds;
  }
  set
  {
    DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime();
    this.Created = epoch.AddSeconds(value);
  }
}
Mark Ingram
źródło
119
Nadchodząca platforma .NET 4.6 (która zostanie wydana jeszcze w tym roku) wprowadza obsługę tego. Zobacz DateTimeOffset.FromUnixTimeSecondsi DateTimeOffset.ToUnixTimeSecondsmetody. Istnieją również metody dla milisekundowego czasu uniksowego.
Jeppe Stig Nielsen

Odpowiedzi:

1017

Oto czego potrzebujesz:

public static DateTime UnixTimeStampToDateTime( double unixTimeStamp )
{
    // Unix timestamp is seconds past epoch
    System.DateTime dtDateTime = new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc);
    dtDateTime = dtDateTime.AddSeconds( unixTimeStamp ).ToLocalTime();
    return dtDateTime;
}

Lub w przypadku języka Java (który jest inny, ponieważ znacznik czasu jest wyrażony w milisekundach, a nie sekundach):

public static DateTime JavaTimeStampToDateTime( double javaTimeStamp )
{
    // Java timestamp is milliseconds past epoch
    System.DateTime dtDateTime = new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc);
    dtDateTime = dtDateTime.AddMilliseconds( javaTimeStamp ).ToLocalTime();
    return dtDateTime;
}
ScottCher
źródło
5
Czas w systemie Windows jest obsługiwany przez HAL i tylko z dokładnością w zakresie od 1 ms do 15 ms. Więcej informacji jest dostępnych w Windows Wewnętrznych na stronie 112, jeśli ktoś jest zainteresowany.
Jim Schubert,
16
Ta odpowiedź może skrócić sekundy ... Podwójna liczba zmiennoprzecinkowa. Argumentem powinno być int / long / etc.
ccook
44
Te metody powinny przyjmować long lub int, a nie double. Ponadto w przypadku znaczników czasu Java nie ma potrzeby dzielenia przez 1000 i zaokrąglanie. Po prostu zróbdtDateTime.AddMilliseconds(javaTimeStamp).ToLocalTime();
Justin Johnson
11
Czy właśnie tęskniłeś za „vice versa”? Jak przekonwertować DateTime na znacznik czasu?
Jonny,
38
W .NET Framework 4.6 i nowszych jest teraz static DateTimeOffset.FromUnixMillisecondsi DateTimeOffset.ToUnixMilliseconds.
rookie1024
421

Najnowszą wersję .NET Framework (v4.6) dodała 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 do UTC DateTimeOffset:

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

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

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

long unixTimeStampInMilliseconds = dateTimeOffset.ToUnixTimeMilliseconds();

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

DateTime dateTime = dateTimeOffset.UtcDateTime;
i3arnon
źródło
Nie zamienia to czasu na czas lokalny. Otrzymasz UTC, jeśli użyjesz DateTimeOffset.FromUnixTimeSeconds ().
Berend de Boer
4
@BerenddeBoer Możesz użyć, ToLocalTimejeśli chcesz.
i3arnon
1
Aby uzyskać aktualny czas, możesz użyćlong unixMilliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Dan Diplo
219

Datownik do UNIX-a:

public static double DateTimeToUnixTimestamp(DateTime dateTime)
{
    return (TimeZoneInfo.ConvertTimeToUtc(dateTime) - 
           new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc)).TotalSeconds;
}
Dmitrij Fedorkow
źródło
47

Z Wikipedii :

UTC nie zmienia się wraz ze zmianą pór roku, ale czas lokalny lub czas cywilny mogą ulec zmianie, jeśli jurysdykcja strefy czasowej przestrzega czasu letniego (czas letni). Na przykład czas lokalny na wschodnim wybrzeżu Stanów Zjednoczonych jest pięć godzin za UTC w zimie, ale cztery godziny w tyle, gdy obserwuje się tam czas letni.

Oto mój kod:

TimeSpan span = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0,DateTimeKind.Utc));
double unixTime = span.TotalSeconds;
gl051
źródło
2
ale to zwraca podwójność, myślę, że trzeba rzucić zbyt długo?
knocte
30

Bądź ostrożny, jeśli potrzebujesz precyzji wyższej niż milisekundy!

Metody .NET (v4.6) (np. FromUnixTimeMilliseconds ) nie zapewniają tej precyzji.

AddSeconds i AddMilliseconds również odcinają mikrosekundy w podwójnym.

Te wersje mają wysoką precyzję:

Unix -> DateTime

public static DateTime UnixTimestampToDateTime(double unixTime)
{
    DateTime unixStart = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
    long unixTimeStampInTicks = (long) (unixTime * TimeSpan.TicksPerSecond);
    return new DateTime(unixStart.Ticks + unixTimeStampInTicks, System.DateTimeKind.Utc);
}

DateTime -> Unix

public static double DateTimeToUnixTimestamp(DateTime dateTime)
{
    DateTime unixStart = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
    long unixTimeStampInTicks = (dateTime.ToUniversalTime() - unixStart).Ticks;
    return (double) unixTimeStampInTicks / TimeSpan.TicksPerSecond;
}
Felix Keil
źródło
2
To jest poprawna odpowiedź. Inni otrzymują niepoprawną strefę czasową podczas konwersji z datownika.
IamIC
dla DateTime-> Java, po prostu [kod] zwraca (długi) unixTimeStampInTicks / TimeSpan.TicksPerMilliSecond; [/ code]
maks.
Więc u ciebie UnixTimestampToDateTimedostarczony unixTimejest nadal w kilka sekund, prawda?
Ngoc Pham
@NgocPham tak to jest
Felix Keil
14

Zobacz IdentityModel.EpochTimeExtensions

public static class EpochTimeExtensions
{
    /// <summary>
    /// Converts the given date value to epoch time.
    /// </summary>
    public static long ToEpochTime(this DateTime dateTime)
    {
        var date = dateTime.ToUniversalTime();
        var ticks = date.Ticks - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).Ticks;
        var ts = ticks / TimeSpan.TicksPerSecond;
        return ts;
    }

    /// <summary>
    /// Converts the given date value to epoch time.
    /// </summary>
    public static long ToEpochTime(this DateTimeOffset dateTime)
    {
        var date = dateTime.ToUniversalTime();
        var ticks = date.Ticks - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero).Ticks;
        var ts = ticks / TimeSpan.TicksPerSecond;
        return ts;
    }

    /// <summary>
    /// Converts the given epoch time to a <see cref="DateTime"/> with <see cref="DateTimeKind.Utc"/> kind.
    /// </summary>
    public static DateTime ToDateTimeFromEpoch(this long intDate)
    {
        var timeInTicks = intDate * TimeSpan.TicksPerSecond;
        return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddTicks(timeInTicks);
    }

    /// <summary>
    /// Converts the given epoch time to a UTC <see cref="DateTimeOffset"/>.
    /// </summary>
    public static DateTimeOffset ToDateTimeOffsetFromEpoch(this long intDate)
    {
        var timeInTicks = intDate * TimeSpan.TicksPerSecond;
        return new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero).AddTicks(timeInTicks);
    }
}
orad
źródło
To dobrze, ale sugeruję małą zmianę: użycie typu „long” powinno zostać zmienione na „Int32” lub „int”. „Długi” oznacza, że ​​istnieje znaczna precyzja, ale nie ma. Cała matematyka jest precyzyjna tylko z dokładnością do 1 sekundy, więc Int32 byłby bardziej sugestywny, czego można oczekiwać od uniksowego znacznika czasu
JamesHoux,
3
Myślę, że to dlatego, że DateTime.Ticksjest Int64 (długi), więc unikają dodatkowej niezaznaczonej obsady.
orad
10

Aby uzupełnić odpowiedź ScottChera, ostatnio znalazłem się w irytującym scenariuszu, w którym zarówno sekundy, jak i milisekundy znaczników czasu UNIX arbitralnie mieszają się w zestawie danych wejściowych. Poniższy kod wydaje się obsługiwać to dobrze:

static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
static readonly double MaxUnixSeconds = (DateTime.MaxValue - UnixEpoch).TotalSeconds;

public static DateTime UnixTimeStampToDateTime(double unixTimeStamp)
{
   return unixTimeStamp > MaxUnixSeconds
      ? UnixEpoch.AddMilliseconds(unixTimeStamp)
      : UnixEpoch.AddSeconds(unixTimeStamp);
}
Chris Thoman
źródło
1
Bądź ostrożny, gdy nie używasz argumentu DateTimeKind, ponieważ skonstruowana data i godzina będą w czasie lokalnym komputera (dzięki za kod, Chris)!
Sam Grondahl,
1
Uwaga - nie będzie to działać w przypadku uniksowych znaczników czasu dla dat sprzed 11 stycznia 1978 r., Jeśli są one reprezentowane w milisekundach. Datownik uniksowy 253324800 (sekundy) podaje prawidłową datę 11.01.1978, natomiast reprezentacja milisekund 253324800000 podaje datę 18.07.9997. To mogło zadziałać dla twojego zestawu danych, ale nie jest to ogólne rozwiązanie.
Øyvind
8

Uniksowa konwersja czasu jest nowością w .NET Framework 4.6.

Teraz możesz łatwiej konwertować wartości daty i godziny na lub z typów .NET Framework i czasu uniksowego. Może to być konieczne na przykład podczas konwersji wartości czasu między klientem JavaScript a serwerem .NET. Następujące interfejsy API zostały dodane do struktury DateTimeOffset :

static DateTimeOffset FromUnixTimeSeconds(long seconds)
static DateTimeOffset FromUnixTimeMilliseconds(long milliseconds)
long DateTimeOffset.ToUnixTimeSeconds()
long DateTimeOffset.ToUnixTimeMilliseconds()
Fred
źródło
To nie daje czasu lokalnego, dostajesz UTC.
Berend de Boer
@BerenddeBoer To rozsądne ustawienie domyślne. Następnie możesz zastosować niestandardowe przesunięcie, jak chcesz.
Deilan
1
@BerenddeBoer To źle rozumie, czym jest czas uniksowy. Czas uniksowy to sekundy od północy, 1 stycznia 1970 r., UTC. Nie ma znaczenia, gdzie jesteś, liczba sekund od tej epoki się nie zmienia. Przekształcenie go w czytelny dla człowieka wyświetlacz czasu lokalnego jest odrębny od tej uniwersalnej reprezentacji, tak jak powinno być.
Tanktalus,
5

Znalazłem właściwą odpowiedź, porównując konwersję z 1/1/1970 bez korekty czasu lokalnego;

DateTime date = new DateTime(2011, 4, 1, 12, 0, 0, 0);
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);
TimeSpan span = (date - epoch);
double unixTime =span.TotalSeconds;
n8CodeGuru
źródło
4
var dt = DateTime.Now; 
var unixTime = ((DateTimeOffset)dt).ToUnixTimeSeconds();

1510396991

var dt = DateTimeOffset.FromUnixTimeSeconds(1510396991);

// [11.11.2017 10:43:11 +00: 00]

mesut
źródło
4

W .net 4.6 możesz to zrobić:

var dateTime = DateTimeOffset.FromUnixTimeSeconds(unixDateTime).DateTime;
Yang Zhang
źródło
3
DateTime unixEpoch = DateTime.ParseExact("1970-01-01", "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture);
DateTime convertedTime = unixEpoch.AddMilliseconds(unixTimeInMillisconds);

Oczywiście można stworzyć unixEpochglobalną statyczną wartość, więc wystarczy, że pojawi się ona tylko raz w projekcie, i można jej użyć, AddSecondsjeśli czas UNIX jest w sekundach.

Aby przejść w drugą stronę:

double unixTimeInMilliseconds = timeToConvert.Subtract(unixEpoch).TotalMilliseconds;

Obetnij do Int64 i / lub użyj TotalSecondsw razie potrzeby.

Hot Licks
źródło
3

Napisał najprostsze rozszerzenie, które działa dla nas. Jeśli ktoś tego szuka ...

public static class DateTimeExtensions
{
    public static DateTime FromUnixTimeStampToDateTime(this string unixTimeStamp)
    {

        return DateTimeOffset.FromUnixTimeSeconds(long.Parse(unixTimeStamp)).UtcDateTime;
    }
}
Riyaz Hameed
źródło
3
System.DateTimeOffset.Now.ToUnixTimeSeconds()
AMieres
źródło
2

Tik uniksowy trwa 1 sekundę (o ile dobrze pamiętam), a tik .NET to 100 nanosekund.

Jeśli masz problemy z nanosekundami, możesz spróbować użyć AddTick (wartość 10000000 *).

Luk
źródło
3
Unix wyprzedza epokę - 1/1/70.
ScottCher
1

Musiałem przekonwertować strukturę czasową (sekundy, mikrosekundy) zawierającą UNIX timena DateTimebez utraty precyzji i nie znalazłem tutaj odpowiedzi, więc pomyślałem, że mogę dodać moją:

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
1

Możesz użyć DateTimeOffset .

Na przykład. Mam obiekt DateTime

var dateTime=new DateTime();

Jeśli chcę przekonwertować go na uniksowe znaczniki czasu, mogę to osiągnąć w następujący sposób

var unixTimeSeconds= new DateTimeOffset(dateTime).ToUnixTimeSeconds()

Aby uzyskać więcej informacji, odwiedź ten link: Metoda DateTimeOffset.ToUnixTimeSeconds

Ramil Alijew
źródło
0
public static class UnixTime
    {
        private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);

        public static DateTime UnixTimeToDateTime(double unixTimeStamp)
        {
            return Epoch.AddSeconds(unixTimeStamp).ToUniversalTime();
        }
    }

możesz wywołać UnixTime.UnixTimeToDateTime (double datetime))

madan
źródło
-2

W przypadku .NET 4.6 i nowszych:

public static class UnixDateTime
{
    public static DateTimeOffset FromUnixTimeSeconds(long seconds)
    {
        if (seconds < -62135596800L || seconds > 253402300799L)
            throw new ArgumentOutOfRangeException("seconds", seconds, "");

        return new DateTimeOffset(seconds * 10000000L + 621355968000000000L, TimeSpan.Zero);
    }

    public static DateTimeOffset FromUnixTimeMilliseconds(long milliseconds)
    {
        if (milliseconds < -62135596800000L || milliseconds > 253402300799999L)
            throw new ArgumentOutOfRangeException("milliseconds", milliseconds, "");

        return new DateTimeOffset(milliseconds * 10000L + 621355968000000000L, TimeSpan.Zero);
    }

    public static long ToUnixTimeSeconds(this DateTimeOffset utcDateTime)
    {
        return utcDateTime.Ticks / 10000000L - 62135596800L;
    }

    public static long ToUnixTimeMilliseconds(this DateTimeOffset utcDateTime)
    {
        return utcDateTime.Ticks / 10000L - 62135596800000L;
    }

    [Test]
    public void UnixSeconds()
    {
        DateTime utcNow = DateTime.UtcNow;
        DateTimeOffset utcNowOffset = new DateTimeOffset(utcNow);

        long unixTimestampInSeconds = utcNowOffset.ToUnixTimeSeconds();

        DateTimeOffset utcNowOffsetTest = UnixDateTime.FromUnixTimeSeconds(unixTimestampInSeconds);

        Assert.AreEqual(utcNowOffset.Year, utcNowOffsetTest.Year);
        Assert.AreEqual(utcNowOffset.Month, utcNowOffsetTest.Month);
        Assert.AreEqual(utcNowOffset.Date, utcNowOffsetTest.Date);
        Assert.AreEqual(utcNowOffset.Hour, utcNowOffsetTest.Hour);
        Assert.AreEqual(utcNowOffset.Minute, utcNowOffsetTest.Minute);
        Assert.AreEqual(utcNowOffset.Second, utcNowOffsetTest.Second);
    }

    [Test]
    public void UnixMilliseconds()
    {
        DateTime utcNow = DateTime.UtcNow;
        DateTimeOffset utcNowOffset = new DateTimeOffset(utcNow);

        long unixTimestampInMilliseconds = utcNowOffset.ToUnixTimeMilliseconds();

        DateTimeOffset utcNowOffsetTest = UnixDateTime.FromUnixTimeMilliseconds(unixTimestampInMilliseconds);

        Assert.AreEqual(utcNowOffset.Year, utcNowOffsetTest.Year);
        Assert.AreEqual(utcNowOffset.Month, utcNowOffsetTest.Month);
        Assert.AreEqual(utcNowOffset.Date, utcNowOffsetTest.Date);
        Assert.AreEqual(utcNowOffset.Hour, utcNowOffsetTest.Hour);
        Assert.AreEqual(utcNowOffset.Minute, utcNowOffsetTest.Minute);
        Assert.AreEqual(utcNowOffset.Second, utcNowOffsetTest.Second);
        Assert.AreEqual(utcNowOffset.Millisecond, utcNowOffsetTest.Millisecond);
    }
}
superlogiczny
źródło
4
Nie rozumiem. W .NET 4.6 BCL ma już te metody (patrz np. Mój komentarz do powyższego pytania lub niektóre inne nowe odpowiedzi (2015). Więc po co je ponownie pisać? Czy miałeś na myśli, że Twoja odpowiedź była rozwiązanie dla wersji wcześniejszych niż 4.6?
Jeppe Stig Nielsen