Como você converte o tempo da época em c #?

377

Como você converte o tempo da época Unix em tempo real em C #? (Época começando em 1/1/1970)

hsatterwhite
fonte
11
A menos que esteja faltando alguma coisa, a "época" é simplesmente o ponto de origem de um esquema de cronometragem específico. Os exemplos incluem 1/1/0001, 1/1/1970 e 1/1/2000. É mais um atributo de um esquema do que de um esquema (por exemplo, Julian).
Bob Kaufman
8
Tempo desde a época é o número de segundos desde 1 de janeiro de 1970, UTC.
Taylor Leese
13
@ Taylor Essa é a época do tempo unix, e provavelmente está certa, mas não é a única época válida. Os usuários do Unix time não devem se confundir nesse ponto.
Joel Coehoorn
Dup, com outras respostas: stackoverflow.com/q/3354893/712526
jpaugh

Respostas:

563

Presumo que você esteja falando da hora do Unix , que é definida como o número de segundos desde a meia-noite (UTC) de 1º de janeiro 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
fonte
74
Para que isso funcionasse corretamente, tive que alterar .AddSeconds para .AddMilliseconds. Você precisará saber se o seu número é proveniente de segundos ou milissegundos para obter o resultado correto. Por exemplo, a seguinte data: 1406310305188 (25 de julho de 2014). O epochconverter.com também permitirá que você verifique seus resultados de conversão.
Jrandomuser
5
Você deve alterar o tipo de parâmetro para double (porque AddSeconds aceita double e, portanto, reduzirá para double) ou adicionar um aviso à descrição do método, de que apenas 53 dos 64 bits de precisão no argumento serão preservados.
Tomosius
6
@jrandomuser: o tempo da época do Unix é tradicionalmente representado como segundos desde a época. Desde então, tornou-se comum o uso de milissegundos desde The Epoch (por exemplo, JavaScript), mas a definição clássica é segundos. Resumindo, saiba qual é o seu valor de entrada (segundos, milissegundos, ticks, o que for) e use o AddXYZmétodo certo .
TJ Crowder
Primeiro tente com AddMilliseconds e se o ano ainda for 1970, faça AddSeconds. Dessa forma, funcionará o tempo todo sem precisar se preocupar com milissegundos ou segundos. Além disso, você pode evitar uma exceção de transbordamento. Passando um grande número de AddSeconds fará o acidente código
Tono Nam
213

A versão mais recente do .Net (v4.6) acabou de adicionar suporte interno para conversões de horário do Unix. Isso inclui o horário de e para o Unix representado por segundos ou milissegundos.

  • Tempo Unix em segundos para DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset tempo Unix em segundos:

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • Tempo Unix em milissegundos para DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset para o tempo Unix em milissegundos:

long unixTimeStampInMilliseconds= dateTimeOffset.ToUnixTimeMilliseconds();

Nota: Esses métodos são convertidos para e de DateTimeOffset. Para obter uma DateTimerepresentação, basta usar a DateTimeOffset.DateTimepropriedade:

DateTime dateTime = dateTimeOffset.UtcDateTime;
i3arnon
fonte
11
Estou recebendo 'DateTimeOffset' does not contain a definition for 'FromUnixTimeSeconds'Como resolver isso?
Happy Bird
@HappyBird Você está no .NET 4.6 ou superior?
I3arnon
A mesma coisa - 4.7.2 e não tem nenhum método FromUnixTimeMilliseconds para DateTimeOffset ...
Mikhail_Sam
Deixa comigo. Não preciso criar um novo objeto. É um método estático.
21418 Mikhail_Sam #
Achei os valores padrão um pouco confusos à primeira vista. Bc 1000 é o fator para converter de milis para segundos.
BluE
169

Com todo o crédito a LukeH, reuni alguns métodos de extensão para facilitar o uso:

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

Observe o comentário abaixo de CodesInChaos de que o exemplo acima FromUnixTimeretorna a DateTimecom a Kindde Utc, o que é bom, mas o acima ToUnixTimeé muito mais suspeito, pois não explica o tipo de DateTimedado date. Para permitir date's Kindser tanto Utcou 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);
}

ToUniversalTimeirá converter um Local(ou Unspecified) DateTimepara Utc.

se você não quiser criar a instância DateTime da época ao passar do DateTime para a época, também poderá:

public static long ToUnixTime(this DateTime date)
{
    return (date.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
}
Ben Cull
fonte
6
ToUnixTimesó funciona corretamente se a data estiver em Utc. Adicione um cheque ou converta-o. (Pessoalmente eu prefiro o cheque)
CodesInChaos
2
Apenas passei a última hora descobrindo por que isso não funciona. Você precisa trabalhar em milliseconds não segundos !!!
217129 KristianB #
7
@KristianB: "O tempo Unix" é tradicionalmente segundos, e não milissegundos, desde The Epoch, embora hoje em dia eu tenha o cuidado de verificar qual definição alguém está usando. Os segundos costumavam ser bons o suficiente e nos davam um intervalo razoável de ambos os lados do The Epoch em valores de 32 bits assinados. (E é por isso que depois das 3:14 da manhã de 19 de janeiro de 2038 GMT pode ser um mau momento para alguns ...) Usar milissegundos é uma prática mais moderna, graças ao fato de podermos rotineiramente gerar valores de 64 bits (ambos integrados). e precisão dupla IEEE-754) ...
TJ Crowder
5
Obrigado pelo código. Apenas uma pequena recomendação ao criar a base da Época: defina explicitamente o valor em milissegundos como 0. ie var epoch = new DateTime (1970, 1, 1, 0 / * h * /, 0 / * m * /, 0 / * s * /, 0 / * ms * /, DateTimeKind.Utc); Se você não o definir explicitamente, o valor em milissegundos parece sair como 1. Isso causou algumas inconsistências nos meus testes.
precisa saber é o seguinte
11
Você deve usar AddMillisecondse usar o Double NOT Float. Caso contrário, você terminará com um horário errado.
Axel
25

Você realmente deseja adicionar milissegundos (milissegundos), não segundos. A adição de segundos fornecerá uma exceção fora do intervalo.

Darya
fonte
Por que é que? epochconverter.com Diz que você adiciona o número de segundos desde 1/1/970 e não ms.
Jamie R Rytlewski
Se você está indo de ms, você obviamente quer AddMillise se você está começando a partir de segundos, você obviamente quer AddSeconds.
21714 Shoe
Eu tive o mesmo problema que estava ficando fora de alcance ao usar segundos. O tempo unix que eu estava tentando converter foi em milissegundos. Eu pensei que era em segundos. Eu acho que algum tempo unix é medido em milissegundos.
DoodleKana
O tempo Unix geralmente é expresso em segundos, mas 0,001 é um número válido de segundos (= 1 ms). Em caso de dúvida, use a máxima precisão possível.
Scott
9

Se você quer um melhor desempenho, pode usar esta versão.

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 uma referência rápida (BenchmarkDotNet) sob net471, recebo 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 |

2x mais rápido que a versão de LukeH (se for o desempenho)

É semelhante a como o DateTime funciona internamente.

Jiri Sykora
fonte
9

Use o método DateTimeOffset.ToUnixTimeMilliseconds () Retorna o número de milissegundos decorridos desde 1970-01-01T00: 00: 00.000Z.

Isso é suportado apenas no Framework 4.6 ou superior

var EPOCH = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

Está bem documentado aqui DateTimeOffset.ToUnixTimeMilliseconds

A outra saída é usar o seguinte

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

Para obter o EPOCH apenas com segundos, você pode usar

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

e converta o Epochpara DateTimecom o seguinte método

private DateTime Epoch2UTCNow(int epoch) 
{
    return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(epoch); 
}
Vinod Srivastav
fonte
DateTime.Ticks - cada marca é "cem nanossegundos", tornando-se uma "coisa" extra a ser lembrada. Se omitir os dois .Ticks, você recuperaria uma boa instância TimeSpan da subtração 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);
}

Deve usar ToUniversalTime () para o objeto DateTime.

Green Su
fonte
5

Eu uso os seguintes métodos de extensão para conversão 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
fonte
2

Para não se preocupar em usar milissegundos ou segundos, basta:

    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 o tempo da época for em segundos, não haverá como passar o ano de 1972 adicionando milissegundos.

Tono Nam
fonte
1

Se você não estiver usando o 4.6, isso pode ajudar. Origem: 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
fonte
Obrigado, por exemplo, da JWT. By the way, para usá-lo, basta usar: using Microsoft.IdentityModel.Tokens; ... EpochTime.GetIntDate(dateTime);
liquide
0

Caso você precise converter uma estrutura timeval (segundos, microssegundos) contendo UNIX timepara DateTimesem perder a precisão, é assim:

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

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

Saikat Chakraborty
fonte
-4

Aqui está a minha solução:

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
fonte
7
isso explica anos bissextos e segundos bissextos, etc.?
precisa
11
Para expandir sobre o comentário anterior, aqui está um pequeno vídeo que explica por que o tempo é complicado e por que você não deve tentar fazê-lo sozinho: youtube.com/watch?v=-5wpm-gesOY
vmrob