Come si converte il tempo in C #?


377

Come si converte il tempo di Unix in tempo reale in C #? (Epoca inizio 1/1/1970)


1
A meno che non mi manchi qualcosa, l '"epoca" è semplicemente il punto di origine di un particolare schema di cronometraggio. Gli esempi includono 1/1/0001, 1/1/1970 e 1/1/2000. È più un attributo di uno schema piuttosto che uno schema (ad esempio, Julian) stesso.
Bob Kaufman,

8
Tempo dall'epoca è il numero di secondi dal 1 ° gennaio 1970 UTC.
Taylor Leese,

13
@Taylor Questa è l'epoca del tempo unix, ed è probabilmente giusto, ma non è l'unica epoca valida. Gli utenti di Unix time non devono confondersi su questo punto.
Joel Coehoorn,

Dup, con altre risposte: stackoverflow.com/q/3354893/712526
jpaugh

Risposte:


563

Presumo che intendi l' ora di Unix , che è definita come il numero di secondi dalla mezzanotte (UTC) del 1 ° gennaio 1970.

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

74
Per farlo funzionare correttamente ho dovuto cambiare .AddSeconds in .AddMilliseconds. Dovrai sapere se il tuo numero proviene da Secondi o Millisecondi per ottenere il risultato corretto. Ad esempio, la seguente data: 1406310305188 (25 luglio 2014). epochconverter.com ti consentirà anche di verificare i risultati della conversione.
jrandomuser,

5
È necessario modificare il tipo di parametro su double (poiché AddSeconds accetta double e quindi verrà downcast su double) o aggiungere una dichiarazione di non responsabilità alla descrizione del metodo che verranno preservati solo 53 bit di precisione su 64 nell'argomento.
tomosius

6
@jrandomuser: il tempo di epoca Unix è tradizionalmente rappresentato come secondi dall'epoca. Da allora è diventato comune usare millisecondi da The Epoch (ad esempio JavaScript), ma la definizione classica è secondi. In conclusione, basta sapere qual è il valore di input (secondi, millisecondi, tick, qualunque cosa) e utilizzare il AddXYZmetodo giusto .
TJ Crowder,

Prima prova con AddMilliseconds e se l'anno è ancora 1970, fai AddSeconds. In questo modo funzionerà continuamente senza doversi preoccupare di millisecondi o secondi. Inoltre puoi prevenire un'escissione di overflow. Il passaggio di un numero elevato a AddSeconds comporterà l'arresto anomalo del codice
Tono Nam,

213

L' ultima versione di .Net (v4.6) ha appena aggiunto il supporto integrato per le conversioni temporali Unix. Ciò include sia il tempo di andata e ritorno di Unix rappresentato da secondi o millisecondi.

  • Tempo Unix in secondi per DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset tempo Unix in secondi:

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • Tempo Unix in millisecondi per DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset al tempo Unix in millisecondi:

long unixTimeStampInMilliseconds= dateTimeOffset.ToUnixTimeMilliseconds();

Nota: questi metodi vengono convertiti da e verso DateTimeOffset. Per ottenere una DateTimerappresentazione è sufficiente utilizzare la DateTimeOffset.DateTimeproprietà:

DateTime dateTime = dateTimeOffset.UtcDateTime;

1
Sto ottenendo 'DateTimeOffset' does not contain a definition for 'FromUnixTimeSeconds'Come potrei fare per risolvere questo?
Happy Bird,

@HappyBird Sei su .NET 4.6 o versioni successive?
i3arnon,

La stessa cosa - 4.7.2 e non ha un metodo FromUnixTimeMilliseconds per DateTimeOffset ...
Mikhail_Sam

Capito. Non ho bisogno di creare un nuovo oggetto. È un metodo statico.
Mikhail_Sam,

Ho trovato i valori predefiniti un po 'confusi a prima vista. Bc 1000 è il fattore per convertire da millis a secondi.
BluE

169

Con tutto il merito di LukeH, ho messo insieme alcuni metodi di estensione per un facile utilizzo:

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

Nota il commento qui sotto di CodesInChaos che quanto sopra FromUnixTimerestituisce a DateTimecon a Kinddi Utc, il che va bene, ma quanto sopra ToUnixTimeè molto più sospetto in quanto non tiene conto del tipo di DateTimedato date. Per consentire date's Kindessere uno Utco Local, uso 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);
}

ToUniversalTimeconvertirà un Local(o Unspecified) DateTimein Utc.

se non si desidera creare l'istanza DateTime di epoca quando ci si sposta da DateTime a epoca è possibile anche:

public static long ToUnixTime(this DateTime date)
{
    return (date.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
}

6
ToUnixTimefunziona correttamente solo se la data è in Utc. Aggiungi un segno di spunta o convertilo. (Personalmente preferisco il controllo)
CodesInChaos,

2
Ho appena trascorso l'ultima ora a capire perché questo non funziona. Devi lavorare in milliseconds non secondi !!!
KristianB,

7
@KristianB: "Unix time" è tradizionalmente secondi, non millisecondi, da The Epoch, anche se in questi giorni sto attento a verificare quale definizione sta usando qualcuno. I secondi erano abbastanza buoni e ci davano un intervallo ragionevole su entrambi i lati di The Epoch in valori con segno a 32 bit. (Ed è per questo che poco dopo le 3:14 del 19 gennaio 2038 GMT potrebbe essere un brutto momento per alcuni ...) L'uso dei millisecondi è una pratica più moderna grazie alla nostra capacità ordinaria di generare valori a 64 bit (entrambi integrali e doppia precisione IEEE-754) ...
TJ Crowder,

5
Grazie per il codice Solo una leggera raccomandazione durante la creazione della base Epoch: assicurati di impostare esplicitamente il valore del Millisecondo su 0. ie var epoch = new DateTime (1970, 1, 1, 0 / * h * /, 0 / * m * /, 0 / * s * /, 0 / * ms * /, DateTimeKind.Utc); Se non lo imposti esplicitamente, il valore in millisecondi sembra emergere come 1. Ciò ha causato alcune incoerenze nei miei test.
ctrlplusb,

1
Dovresti usare AddMillisecondse dovresti usare Double NOT Float. Altrimenti finirai con un momento sbagliato.
Axel

25

In realtà si desidera aggiungere Millisecondi (millisecondi), non secondi. L'aggiunta di secondi ti darà un'eccezione fuori portata.


Perché? epochconverter.com Dice che si aggiunge il numero di secondi dal 1/1/970 non ms.
Jamie R Rytlewski,

Se vai da ms, ovviamente, vuoi, AddMillise se stai partendo da pochi secondi, ovviamente, vuoi AddSeconds.
Scarpa

Ho avuto lo stesso problema che stavo continuando a uscire dal raggio d'azione usando i secondi. Il tempo unix che stavo cercando di convertire era in millisecondi. Ho pensato che fosse in pochi secondi. Immagino che un po 'di tempo unix sia misurato in millisecondi.
DoodleKana,

Il tempo Unix è generalmente espresso in secondi, ma 0,001 è un numero valido di secondi (= 1 ms). In caso di dubbi, basta usare la massima precisione possibile.
Scott,

9

Se vuoi prestazioni migliori puoi usare questa versione.

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

Da un rapido benchmark (BenchmarkDotNet) sotto net471 ottengo questo numero:

        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 più veloce rispetto alla versione di LukeH (se la performance mater)

Questo è simile al funzionamento interno di DateTime.


9

Usa il metodo DateTimeOffset.ToUnixTimeMilliseconds () Restituisce il numero di millisecondi trascorsi dal 1970-01-01T00: 00: 00.000Z.

Questo è supportato solo con Framework 4.6 o versioni successive

var EPOCH = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

È ben documentato qui DateTimeOffset.ToUnixTimeMilliseconds

L'altra via d'uscita è usare quanto segue

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

Per ottenere l'EPOCH in pochi secondi puoi usare

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

e converti Epochin DateTimecon il seguente metodo

private DateTime Epoch2UTCNow(int epoch) 
{
    return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(epoch); 
}

DateTime.Ticks - ogni segno di spunta è "cento nanosecondi", rendendolo una "cosa" in più da ricordare. Se si omettono entrambi .Ticks, si otterrebbe una bella istanza TimeSpan dalla sottostrazione 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);
}

Dovrebbe usare ToUniversalTime () per l'oggetto DateTime.


5

Uso i seguenti metodi di estensione per la conversione di epoca

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

    }

2

Per non preoccuparti di usare millisecondi o secondi, fai semplicemente:

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

Se il tempo è in secondi, non è possibile passare l'anno 1972 aggiungendo millisecondi.


1

Se non si utilizza 4.6, questo può aiutare 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;
    }    

Grazie ad esempio da JWT. A proposito, per usarlo, basta usare: using Microsoft.IdentityModel.Tokens; ... EpochTime.GetIntDate(dateTime);
liquide

0

In caso di necessità di convertire una struct timeval (secondi, microsecondi) contenente UNIX timea DateTime, senza perdere in precisione, questo è il modo:

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


-4

Ecco la mia soluzione:

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

7
fa questo conto per anni bisestili e secondi bisestili ecc?
Jodrell,

1
Per espandere il commento precedente, ecco un breve video che spiega perché il tempo è complicato e perché non dovresti provare a farlo da solo: youtube.com/watch?v=-5wpm-gesOY
vmrob
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.