Comment puis-je convertir un horodatage Unix en DateTime et vice versa?

755

Il y a cet exemple de code, mais ensuite il commence à parler de problèmes de milliseconde / nanoseconde.

La même question se pose sur MSDN, Secondes depuis l'époque Unix en C # .

Voici ce que j'ai jusqu'à présent:

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
la source
119
Le prochain .NET 4.6 (qui sera publié plus tard cette année) introduit la prise en charge de cela. Voir DateTimeOffset.FromUnixTimeSecondset DateTimeOffset.ToUnixTimeSecondsméthodes. Il existe également des méthodes pour la milliseconde unix-time.
Jeppe Stig Nielsen

Réponses:

1018

Voici ce dont vous avez besoin:

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

Ou, pour Java (qui est différent car l'horodatage est en millisecondes, pas en secondes):

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
la source
5
Le temps dans Windows est géré par HAL et n'est presque précis qu'en 1 ms à 15 ms. Plus d'informations sont disponibles dans Windows Internals autour de la page 112, si quelqu'un est intéressé.
Jim Schubert
16
Cette réponse risque de tronquer les secondes ... Un double est un nombre flottant. L'argument doit être int / long / etc.
ccook
44
Ces méthodes doivent accepter un long ou un entier, pas un double. De plus, pour les horodatages Java, il n'est pas nécessaire de diviser par 1000 et d'arrondir. Just dodtDateTime.AddMilliseconds(javaTimeStamp).ToLocalTime();
Justin Johnson
11
Vous venez de manquer le "vice versa"? Comment convertir un DateTime en horodatage?
Jonny
39
Pour le .NET Framework 4.6 et supérieur, il existe maintenant static DateTimeOffset.FromUnixMillisecondset DateTimeOffset.ToUnixMilliseconds.
rookie1024
422

La dernière version de .NET (v4.6) a ajouté la prise en charge intégrée pour les conversions de temps Unix. Cela inclut le temps vers et depuis Unix représenté par des secondes ou des millisecondes.

  • Temps Unix en secondes en UTC DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset en temps Unix en secondes:

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • Temps Unix en millisecondes en UTC DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset en Unix en millisecondes:

long unixTimeStampInMilliseconds = dateTimeOffset.ToUnixTimeMilliseconds();

Remarque: Ces méthodes convertissent vers et depuis un UTC DateTimeOffset. Pour obtenir une DateTimereprésentation, utilisez simplement les propriétés DateTimeOffset.UtcDateTimeou DateTimeOffset.LocalDateTime:

DateTime dateTime = dateTimeOffset.UtcDateTime;
i3arnon
la source
Cela ne convertit pas l'heure en heure locale. Vous obtenez UTC si vous utilisez DateTimeOffset.FromUnixTimeSeconds ().
Berend de Boer
4
@BerenddeBoer Vous pouvez utiliser ToLocalTimesi vous le souhaitez.
i3arnon
1
Pour obtenir l'heure actuelle, vous pouvez utiliserlong unixMilliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Dan Diplo
219

DateTime à l'horodatage UNIX:

public static double DateTimeToUnixTimestamp(DateTime dateTime)
{
    return (TimeZoneInfo.ConvertTimeToUtc(dateTime) - 
           new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc)).TotalSeconds;
}
Dmitry Fedorkov
la source
47

De Wikipédia :

L'UTC ne change pas avec un changement de saison, mais l'heure locale ou l'heure civile peut changer si une juridiction de fuseau horaire observe l'heure d'été (heure d'été). Par exemple, l'heure locale sur la côte est des États-Unis a cinq heures de retard sur UTC pendant l'hiver, mais quatre heures de retard alors que l'heure d'été y est observée.

Voici donc mon code:

TimeSpan span = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0,DateTimeKind.Utc));
double unixTime = span.TotalSeconds;
gl051
la source
2
mais cela renvoie un double, je suppose que l'on doit lancer trop longtemps?
knocte
30

Attention, si vous avez besoin d'une précision supérieure aux millisecondes!

Les méthodes .NET (v4.6) (par exemple FromUnixTimeMilliseconds ) ne fournissent pas cette précision.

AddSeconds et AddMilliseconds coupent également les microsecondes dans le double.

Ces versions ont une grande précision:

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
la source
2
Ceci est la bonne réponse. Les autres obtiennent le fuseau horaire incorrect lors de la conversion de l'horodatage.
IamIC
pour DateTime-> Java, juste [code] return (long) unixTimeStampInTicks / TimeSpan.TicksPerMilliSecond; [/ code]
Max
Donc dans votre UnixTimestampToDateTime, le fourni unixTimeest toujours en quelques secondes, non?
Ngoc Pham
@NgocPham oui c'est le cas
Felix Keil
14

Voir 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
la source
C'est bien, mais je suggère une petite modification: l'utilisation du type "long" doit être remplacée par "Int32" ou "int". "Long" implique qu'il y a une précision importante, mais ce n'est pas le cas. Tout le calcul n'est précis qu'à 1 seconde, donc Int32 serait plus suggestif de ce que vous attendez d'un horodatage Unix
JamesHoux
3
Je pense que cela est dû au DateTime.Ticksfait qu'Int64 (long), ils évitent donc une distribution supplémentaire non contrôlée.
2018 à 20h42
10

Pour compléter la réponse de ScottCher, je me suis récemment retrouvé dans le scénario ennuyeux d'avoir des horodatages UNIX en secondes et en millisecondes mélangés arbitrairement dans un ensemble de données d'entrée. Le code suivant semble bien gérer cela:

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
la source
1
Soyez prudent lorsque vous n'utilisez pas l'argument DateTimeKind, car le DateTime construit sera à l'heure locale de l'ordinateur (merci pour le code, Chris)!
Sam Grondahl
1
Attention - cela ne fonctionnera pas pour les horodatages Unix pour les dates antérieures au 11 janvier 1978 si elles sont représentées en millisecondes. Un horodatage Unix de 253324800 (secondes) donne la date correcte du 11.01.1978, tandis que la représentation en millisecondes 253324800000 donne une date du 18.07.9997. Cela a peut-être fonctionné pour votre ensemble de données, mais ce n'est pas une solution générale.
Øyvind
8

La conversion de l'heure Unix est nouvelle dans .NET Framework 4.6.

Vous pouvez désormais convertir plus facilement les valeurs de date et d'heure vers ou depuis les types .NET Framework et l'heure Unix. Cela peut être nécessaire, par exemple, lors de la conversion de valeurs de temps entre un client JavaScript et un serveur .NET. Les API suivantes ont été ajoutées à la structure DateTimeOffset :

static DateTimeOffset FromUnixTimeSeconds(long seconds)
static DateTimeOffset FromUnixTimeMilliseconds(long milliseconds)
long DateTimeOffset.ToUnixTimeSeconds()
long DateTimeOffset.ToUnixTimeMilliseconds()
Fred
la source
Cela ne vous donne pas l'heure locale, vous obtenez UTC.
Berend de Boer
@BerenddeBoer C'est un défaut raisonnable. Vous pouvez ensuite appliquer un décalage personnalisé comme vous le souhaitez.
Deilan
1
@BerenddeBoer Cela méconnaît ce qu'est le temps Unix. Le temps Unix est en secondes depuis minuit, le 1er janvier 1970, UTC. Peu importe où vous êtes, le nombre de secondes depuis cette époque ne change pas. Le convertir en affichage de l'heure locale lisible par l'homme est séparé de cette représentation universelle, comme il se doit.
Tanktalus
5

J'ai trouvé la bonne réponse simplement en comparant la conversion au 1/1/1970 sans l'ajustement de l'heure locale;

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
la source
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
la source
4

Depuis .net 4.6, vous pouvez faire ceci:

var dateTime = DateTimeOffset.FromUnixTimeSeconds(unixDateTime).DateTime;
Yang Zhang
la source
3
DateTime unixEpoch = DateTime.ParseExact("1970-01-01", "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture);
DateTime convertedTime = unixEpoch.AddMilliseconds(unixTimeInMillisconds);

Bien sûr, on peut créer unixEpochune statique globale, il ne doit donc apparaître qu'une seule fois dans votre projet, et on peut l'utiliser AddSecondssi l'heure UNIX est en secondes.

Pour aller dans l'autre sens:

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

Tronquez en Int64 et / ou utilisez TotalSecondsau besoin.

Hot Licks
la source
3

A écrit une extension la plus simple qui fonctionne pour nous. Si quelqu'un le cherche ...

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

        return DateTimeOffset.FromUnixTimeSeconds(long.Parse(unixTimeStamp)).UtcDateTime;
    }
}
Riyaz Hameed
la source
3
System.DateTimeOffset.Now.ToUnixTimeSeconds()
AMières
la source
2

Un tick Unix est de 1 seconde (si je me souviens bien), et un tick .NET est de 100 nanosecondes.

Si vous rencontrez des problèmes avec les nanosecondes, vous voudrez peut-être essayer d'utiliser AddTick (valeur 10000000 *).

Luk
la source
3
Unix est une seconde après l'époque - qui est 1/1/70.
ScottCher
1

Je avais besoin de convertir une struct timeval (secondes, microsecondes) contenant UNIX timede DateTimesans perte de précision et n'ont pas trouvé une réponse ici , donc je pensais que je pourrais juste ajouter le mien:

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
la source
1

Vous pouvez utiliser DateTimeOffset .

Par exemple. J'ai un objet DateTime

var dateTime=new DateTime();

Si je veux le convertir en horodatages Unix, je peux être réalisé comme suit

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

Pour plus d'informations, veuillez visiter ce lien: Méthode DateTimeOffset.ToUnixTimeSeconds

Ramil Aliyev
la source
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();
        }
    }

vous pouvez appeler UnixTime.UnixTimeToDateTime (double datetime))

madan
la source
-2

Pour .NET 4.6 et versions ultérieures:

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);
    }
}
superlogique
la source
4
Je ne comprends pas. Dans .NET 4.6, la BCL a déjà ces méthodes (voir par exemple mon commentaire à la question ci-dessus, ou certaines des autres nouvelles réponses (2015). Alors, à quoi bon les écrire à nouveau? Vouliez-vous dire que votre réponse était une solution pour les versions antérieures à 4.6?
Jeppe Stig Nielsen