¿Cómo se convierte el tiempo de época en C #?

377

¿Cómo se convierte el tiempo de época de Unix en tiempo real en C #? (Época comenzando el 1/1/1970)

hsatterwhite
fuente
1
A menos que me falte algo, la "época" es simplemente el punto de origen de un esquema de cronometraje particular. Los ejemplos incluyen 1/1/0001, 1/1/1970 y 1/1/2000. Es más un atributo de un esquema que un esquema (por ejemplo, Julian) en sí mismo.
Bob Kaufman
8
El tiempo transcurrido desde la época es el número de segundos desde el 1 de enero de 1970 UTC.
Taylor Leese
13
@Taylor Esa es la época del tiempo de Unix, y probablemente sea la correcta, pero no es la única época válida. Los usuarios de Unix time no deben confundirse en ese punto.
Joel Coehoorn
Dup, con otras respuestas: stackoverflow.com/q/3354893/712526
jpaugh

Respuestas:

563

Supongo que te refieres a la hora de Unix , que se define como el número de segundos desde la medianoche (UTC) del 1 de enero de 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);
LukeH
fuente
74
Para que esto funcione correctamente, tuve que cambiar .AddSeconds a .AddMilliseconds. Necesitará saber si su número proviene de segundos o milisegundos para obtener el resultado correcto. Así, por ejemplo, la siguiente fecha: 1406310305188 (25 de julio de 2014). epochconverter.com también le permitirá verificar sus resultados de conversión.
jrandomuser
55
Debe cambiar el tipo de parámetro a doble (porque AddSeconds acepta doble y, por lo tanto, se convertirá en doble) o agregar un descargo de responsabilidad a la descripción del método de que solo se conservarán 53 de 64 bits de precisión en el argumento.
tomosius
66
@jrandomuser: el tiempo de época de Unix se representa tradicionalmente como segundos desde The Epoch. Desde entonces se ha vuelto común usar milisegundos desde The Epoch (por ejemplo, JavaScript), pero la definición clásica es segundos. En pocas palabras, solo sepa cuál es su valor de entrada (segundos, milisegundos, tics, lo que sea) y use el AddXYZmétodo correcto .
TJ Crowder
Primero intente con AddMilliseconds y si el año aún es 1970, entonces haga AddSeconds. De esta manera funcionará todo el tiempo sin tener que preocuparse por milisegundos o segundos. Además, puede evitar una excisión por desbordamiento. Pasar un gran número a AddSeconds hará que el código se bloquee
Tono Nam
213

La última versión de .Net (v4.6) acaba de agregar soporte incorporado para las conversiones de tiempo Unix. Eso incluye el tiempo hacia y desde Unix representado por segundos o milisegundos.

  • Tiempo de Unix en segundos para DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset al tiempo de Unix en segundos:

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • Tiempo de Unix en milisegundos para DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset al tiempo Unix en milisegundos:

long unixTimeStampInMilliseconds= dateTimeOffset.ToUnixTimeMilliseconds();

Nota: Estos métodos convierten desde y hacia DateTimeOffset. Para obtener una DateTimerepresentación simplemente use la DateTimeOffset.DateTimepropiedad:

DateTime dateTime = dateTimeOffset.UtcDateTime;
i3arnon
fuente
1
Estoy obteniendo 'DateTimeOffset' does not contain a definition for 'FromUnixTimeSeconds'¿Cómo haría para resolver esto?
Happy Bird
@HappyBird ¿Estás en .NET 4.6 o superior?
i3arnon
La misma cosa - 4.7.2 y no tienen ningún método para FromUnixTimeMilliseconds DateTimeOffset ...
Mikhail_Sam
Lo tengo. No necesito crear un nuevo objeto. Es un método estático.
Mikhail_Sam
Los valores predeterminados me parecieron un poco confusos a primera vista. Bc 1000 es el factor para convertir de milis a segundos.
BluE
169

Con todo el crédito a LukeH, he reunido algunos métodos de extensión para un uso fácil:

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

Tenga en cuenta el siguiente comentario de CodesInChaos de que lo anterior FromUnixTimedevuelve un DateTimecon a Kindde Utc, lo cual está bien, pero lo anterior ToUnixTimees mucho más sospechoso porque no explica qué tipo de DateTimedato datees. Para permitir date's Kindser cualquiera Utco Local, el 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) DateTimea Utc.

si no desea crear la instancia de epoch DateTime al pasar de DateTime a epoch, también puede hacer:

public static long ToUnixTime(this DateTime date)
{
    return (date.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
}
Ben Cull
fuente
66
ToUnixTimesolo funciona correctamente si la fecha está en Utc. Agregue un cheque o conviértalo. (Personalmente prefiero el cheque)
CodesInChaos
2
Acabo de pasar la última hora descubriendo por qué esto no funciona. ¡Necesitas trabajar en milliseconds no segundos!
KristianB
77
@KristianB: "Tiempo de Unix" es tradicionalmente segundos, no milisegundos, desde The Epoch, aunque en estos días tengo cuidado de verificar qué definición está usando alguien. Los segundos solían ser lo suficientemente buenos, y nos dieron un rango razonable a ambos lados de The Epoch en valores de 32 bits con signo. (Y es por eso que justo después de las 3:14 am del 19 de enero de 2038 GMT podría ser un mal momento para algunos ...) El uso de milisegundos es una práctica más moderna gracias a que habitualmente podemos arrojar valores de 64 bits (ambos integrales y doble precisión IEEE-754) ...
TJ Crowder
55
Gracias por el codigo. Solo una pequeña recomendación al crear la base Epoch: asegúrese de establecer explícitamente el valor de milisegundos en 0. es decir, var epoch = new DateTime (1970, 1, 1, 0 / * h * /, 0 / * m * /, 0 / * s * /, 0 / * ms * /, DateTimeKind.Utc); Si no lo configura explícitamente, el valor de milisegundos parece salir como 1. Esto causó algunas inconsistencias en mis pruebas.
ctrlplusb
1
Debe usar AddMillisecondsy debe usar Double NOT Float. De lo contrario, terminarás con un mal momento.
Axel
25

En realidad, desea agregar milisegundos (milisegundos), no segundos. Agregar segundos le dará una excepción fuera de rango.

Darya
fuente
¿Porqué es eso? epochconverter.com Dice que agrega el número de segundos desde 1/1/970 no ms.
Jamie R Rytlewski
Si va desde ms, obviamente desea AddMillisy si comienza desde segundos, obviamente desea AddSeconds.
Zapato
Tuve el mismo problema que seguía saliendo del rango cuando usaba segundos. El tiempo de Unix que estaba tratando de convertir fue en milisegundos. Pensé que era en segundos. Supongo que el tiempo unix se mide en milisegundos.
DoodleKana
El tiempo de Unix generalmente se expresa en segundos, pero 0.001 es un número válido de segundos (= 1 ms). En caso de duda, utilice la máxima precisión posible.
Scott
9

Si desea un mejor rendimiento, puede usar esta versión.

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

De un punto de referencia rápido (BenchmarkDotNet) bajo net471 obtengo este número:

        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 |

2 veces más rápido contra la versión de LukeH (si es el rendimiento mater)

Esto es similar al funcionamiento interno de DateTime.

Jiri Sykora
fuente
9

Use el método DateTimeOffset.ToUnixTimeMilliseconds () Devuelve el número de milisegundos que han transcurrido desde 1970-01-01T00: 00: 00.000Z.

Esto solo es compatible con Framework 4.6 o superior

var EPOCH = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

Está bien documentado aquí DateTimeOffset.ToUnixTimeMilliseconds

La otra salida es usar lo siguiente

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

Para obtener el EPOCH con solo segundos, puede usar

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

y convertir el Epocha DateTimecon el siguiente método

private DateTime Epoch2UTCNow(int epoch) 
{
    return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(epoch); 
}
Vinod Srivastav
fuente
DateTime.Ticks : cada tic es "cien nanosegundos", por lo que es una "cosa" adicional para recordar. Si omite ambos .Ticks, uno obtendría una buena instancia de TimeSpan de la resta de 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);
}

Debería usar ToUniversalTime () para el objeto DateTime.

Su verde
fuente
5

Yo uso los siguientes métodos de extensión para la conversión de época

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
fuente
2

Para no preocuparse por usar milisegundos o segundos, simplemente haga lo siguiente:

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

Si el tiempo de la época es en segundos, no hay forma de que pueda pasar el año 1972 agregando milisegundos.

Tono Nam
fuente
1

Si no está utilizando 4.6, esto puede ayudar Fuente: 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
fuente
Gracias por ejemplo de JWT. Por cierto, para usarlo, solo use: using Microsoft.IdentityModel.Tokens; ... EpochTime.GetIntDate(dateTime);
liquide
0

En caso de que necesite convertir una estructura timeval (segundos, microsegundos) que contenga UNIX timea DateTimesin perder precisión, así es como:

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
fuente
0

Desde .Net 4.6 y superior, use DateTimeOffset.Now.ToUnixTimeSeconds ()

Saikat Chakraborty
fuente
-4

Aquí está mi solución:

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
fuente
77
¿esto tiene en cuenta los años bisiestos y los segundos bisiestos, etc.?
Jodrell
1
Para ampliar el comentario anterior, aquí hay un breve video que explica por qué el tiempo es complicado y por qué no debería intentar hacerlo usted mismo: youtube.com/watch?v=-5wpm-gesOY
vmrob