Como posso converter um registro de data e hora do Unix em DateTime e vice-versa?

754

Há esse código de exemplo, mas ele começa a falar sobre problemas de milissegundos / nanossegundos.

A mesma pergunta está no MSDN, segundos desde a época do Unix em C # .

Isto é o que eu tenho até agora:

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
fonte
119
O próximo .NET 4.6 (a ser lançado ainda este ano) apresenta suporte para isso. Veja DateTimeOffset.FromUnixTimeSecondse DateTimeOffset.ToUnixTimeSecondsmétodos. Existem métodos para milissegundos em tempo unix também.
Jeppe Stig Nielsen

Respostas:

1018

Aqui está o que você precisa:

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, para Java (que é diferente porque o registro de data e hora está em milissegundos, não segundos):

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
fonte
5
O tempo no Windows é tratado pelo HAL e somente é quase preciso dentro de 1ms a 15ms. Mais informações estão disponíveis no Windows Internals, na página 112, se alguém estiver interessado.
21712 Jim Schubert
16
Esta resposta corre o risco de truncar os segundos ... Um duplo é um número flutuante. O argumento deve ser int / long / etc.
ccook
44
Esses métodos devem aceitar um longo ou int, não um duplo. Além disso, para os carimbos de hora do Java, não há necessidade de dividir por 1000 e arredondados. Just dodtDateTime.AddMilliseconds(javaTimeStamp).ToLocalTime();
Justin Johnson
11
Você acabou de perder o "vice-versa"? Como convertemos um DateTime em um carimbo de data / hora?
Jonny
38
Para o .NET Framework 4.6 e superior, existe agora static DateTimeOffset.FromUnixMillisecondse DateTimeOffset.ToUnixMilliseconds.
Rickie1024
422

A versão mais recente do .NET (v4.6) adicionou 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 UTC DateTimeOffset:

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

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • Hora Unix em milissegundos para UTC 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 um UTC DateTimeOffset. Para obter uma DateTimerepresentação, basta usar as propriedades DateTimeOffset.UtcDateTimeou DateTimeOffset.LocalDateTime:

DateTime dateTime = dateTimeOffset.UtcDateTime;
i3arnon
fonte
Isso não converte a hora para a hora local. Você obtém o UTC se usar DateTimeOffset.FromUnixTimeSeconds ().
Berend de Boer
4
@BerenddeBoer Você pode usar ToLocalTimese quiser.
I3arnon 28/08/19
1
Para obter o tempo atual você pode usarlong unixMilliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Dan Diplo
219

Data e hora para 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
fonte
47

Da Wikipedia :

O UTC não muda com a mudança de estação, mas a hora local ou a hora civil podem mudar se uma jurisdição de fuso horário observar o horário de verão (horário de verão). Por exemplo, a hora local na costa leste dos Estados Unidos está cinco horas atrás da UTC durante o inverno, mas quatro horas atrasada enquanto o horário de verão é observado lá.

Então este é o meu código:

TimeSpan span = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0,DateTimeKind.Utc));
double unixTime = span.TotalSeconds;
gl051
fonte
2
mas isso retorna um duplo, acho que é preciso lançar a muito tempo?
Knocte
30

Cuidado, se você precisar de precisão maior que milissegundos!

Os métodos .NET (v4.6) (por exemplo, FromUnixTimeMilliseconds ) não fornecem essa precisão.

AddSeconds e AddMilliseconds também cortam os microssegundos no dobro.

Estas versões têm alta precisão:

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
fonte
2
Essa é a resposta correta. Os outros obtêm o fuso horário incorreto na conversão de volta do carimbo de data / hora.
IamIC
para DateTime-> Java, basta [código] retornar (longo) unixTimeStampInTicks / TimeSpan.TicksPerMilliSecond; [/ code]
Max
Então no seu UnixTimestampToDateTime, o fornecido unixTimeainda está em segundos, certo?
Ngoc Pham
@NgocPham sim, é
Felix Keil
14

Consulte 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
fonte
Isso é bom, mas eu sugiro uma pequena alteração: o uso do tipo "long" deve ser alterado para "Int32" ou "int". "Longo" implica em precisão significativa, mas não existe. Toda a matemática só é preciso a 1 segundo para Int32 seria mais sugestivo do que você esperaria de um timestamp Unix
JamesHoux
3
Eu acho que é por DateTime.Ticksser Int64 (longo), então eles estão evitando um elenco extra sem controle.
Orad 14/12
10

Para complementar a resposta de ScottCher, recentemente me vi no cenário irritante de ter carimbos de data e hora UNIX de segundos e milissegundos arbitrariamente misturados em um conjunto de dados de entrada. O código a seguir parece lidar bem com isso:

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
fonte
1
Cuidado ao não usar o argumento DateTimeKind, pois o DateTime construído estará no horário local do computador (obrigado pelo código, Chris)!
Sam Grondahl
1
Cuidado: isso não funcionará para registros de data e hora unix para datas anteriores a 11 de janeiro de 1978, se estiverem representados em milissegundos. Um registro de dados unix de 253324800 (segundos) fornece a data correta de 11.01.1978, enquanto a representação em milissegundos 253324800000 fornece uma data de 18.07.9997. Isso pode ter funcionado para o seu conjunto de dados, mas não é uma solução geral.
Øyvind
8

A conversão de hora Unix é nova no .NET Framework 4.6.

Agora você pode converter mais facilmente valores de data e hora de ou para tipos do .NET Framework e hora do Unix. Isso pode ser necessário, por exemplo, ao converter valores de tempo entre um cliente JavaScript e um servidor .NET. As seguintes APIs foram adicionadas à estrutura DateTimeOffset :

static DateTimeOffset FromUnixTimeSeconds(long seconds)
static DateTimeOffset FromUnixTimeMilliseconds(long milliseconds)
long DateTimeOffset.ToUnixTimeSeconds()
long DateTimeOffset.ToUnixTimeMilliseconds()
Fred
fonte
Isso não indica o horário local, você recebe o UTC.
Berend de Boer
@BerenddeBoer Esse é um padrão razoável. Você pode aplicar um deslocamento personalizado depois disso conforme desejar.
Deilan
1
@BerenddeBoer Isso entende mal o que é o tempo unix. O tempo Unix é segundos desde a meia-noite de 1º de janeiro de 1970, UTC. Não importa onde você esteja, o número de segundos desde a época não muda. A conversão para exibições de hora local legíveis por humanos é separada dessa representação universal, como deveria ser.
Tanktalus 11/09/19
5

Encontrei a resposta certa apenas comparando a conversão com 1/1/1970 sem o ajuste da hora local;

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

No .net 4.6, você pode fazer isso:

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

Obviamente, é possível tornar unixEpochuma estática global, portanto, ela só precisa aparecer uma vez no seu projeto e pode ser usada AddSecondsse o tempo do UNIX for em segundos.

Para seguir o outro caminho:

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

Trunque para Int64 e / ou use TotalSecondsconforme necessário.

Hot Licks
fonte
3

Escreveu uma extensão mais simples que funciona para nós. Se alguém procura ...

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

        return DateTimeOffset.FromUnixTimeSeconds(long.Parse(unixTimeStamp)).UtcDateTime;
    }
}
Riyaz Hameed
fonte
3
System.DateTimeOffset.Now.ToUnixTimeSeconds()
AMieres
fonte
2

Um tick do Unix é de 1 segundo (se bem me lembro) e o tick do .NET é de 100 nanossegundos.

Se você encontrar problemas com nanossegundos, tente usar AddTick (valor 10000000 *).

Luk
fonte
3
O Unix é uma época que passou segundos - que é 1/1/70.
ScottCher
1

I necessário para converter uma struct timeval (segundos, microssegundos) contendo UNIX timea DateTimesem perder precisão e não encontramos uma resposta aqui, então eu pensei que eu só poderia adicionar meu:

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
1

Você pode usar DateTimeOffset .

Por exemplo. Eu tenho o objeto DateTime

var dateTime=new DateTime();

Se eu quiser converter os carimbos de data e hora em Unix, posso obter o seguinte

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

Para obter mais informações, visite este link: DateTimeOffset.ToUnixTimeSeconds

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

você pode chamar UnixTime.UnixTimeToDateTime (data e hora dupla))

madan
fonte
-2

Para o .NET 4.6 e posterior:

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);
    }
}
superlógico
fonte
4
Eu não entendo. No .NET 4.6, a BCL já possui esses métodos (veja, por exemplo, meu comentário à pergunta acima ou algumas das outras novas respostas (2015). Portanto, qual seria o sentido de escrevê-las novamente? uma solução para as versões anteriores para 4,6?
Jeppe Stig Nielsen