Как я могу преобразовать метку времени Unix в DateTime и наоборот?

755

Этот пример кода есть, но затем он начинает говорить о проблемах миллисекунды / наносекунды.

Тот же вопрос на MSDN, секунды, начиная с эпохи Unix в C # .

Вот что у меня так далеко:

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);
  }
}
Марк Инграм
источник
119
Предстоящий .NET 4.6 (будет выпущен позже в этом году) представляет поддержку для этого. Смотрите DateTimeOffset.FromUnixTimeSecondsи DateTimeOffset.ToUnixTimeSecondsметоды. Есть методы для миллисекундного unix-времени.
Джеппе Стиг Нильсен

Ответы:

1018

Вот что вам нужно:

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

Или для Java (который отличается, потому что отметка времени указывается в миллисекундах, а не секундах):

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
источник
5
Время в Windows обрабатывается HAL и только с точностью до 1 мс до 15 мс. Дополнительная информация доступна в Windows Internals на странице 112, если кому-то интересно.
Джим Шуберт
16
Этот ответ рискует усечь секунды ... Двойное число является плавающим числом. Аргумент должен быть int / long / etc.
ccook
44
Эти методы должны принимать long или int, а не double. Кроме того, для отметок времени Java нет необходимости делить на 1000 и округлять. Просто сделайdtDateTime.AddMilliseconds(javaTimeStamp).ToLocalTime();
Джастин Джонсон
11
Вы только что пропустили "наоборот"? Как мы конвертируем DateTime в метку времени?
Джонни
39
Для .NET Framework 4.6 и выше есть сейчас static DateTimeOffset.FromUnixMillisecondsи DateTimeOffset.ToUnixMilliseconds.
rookie1024
422

В последней версии .NET (v4.6) добавлена ​​встроенная поддержка преобразования времени Unix. Это включает в себя время от и до Unix, представленное в секундах или миллисекундах.

  • Время Unix в секундах до UTC DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset Unix время в секундах:

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • Время Unix в миллисекундах до UTC DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset Unix время в миллисекундах:

long unixTimeStampInMilliseconds = dateTimeOffset.ToUnixTimeMilliseconds();

Примечание. Эти методы преобразуют в и из UTC DateTimeOffset. Чтобы получить DateTimeпредставление, просто используйте свойства DateTimeOffset.UtcDateTimeили DateTimeOffset.LocalDateTime:

DateTime dateTime = dateTimeOffset.UtcDateTime;
i3arnon
источник
Это не переводит время в местное время. Вы получаете UTC, если используете DateTimeOffset.FromUnixTimeSeconds ().
Беренд де Бур
4
@BerenddeBoer Вы можете использовать, ToLocalTimeесли хотите.
i3arnon
1
Чтобы узнать текущее время вы можете использоватьlong unixMilliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Dan Diplo
219

Отметка времени DateTime в UNIX:

public static double DateTimeToUnixTimestamp(DateTime dateTime)
{
    return (TimeZoneInfo.ConvertTimeToUtc(dateTime) - 
           new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc)).TotalSeconds;
}
Дмитрий Федорков
источник
47

Из Википедии :

UTC не меняется со сменой сезонов, но местное или гражданское время может измениться, если юрисдикция часового пояса соблюдает переход на летнее время (летнее время). Например, местное время на восточном побережье Соединенных Штатов зимой на пять часов меньше, чем на UTC, но на четыре часа меньше, когда наблюдается летнее время.

Итак, это мой код:

TimeSpan span = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0,DateTimeKind.Utc));
double unixTime = span.TotalSeconds;
gl051
источник
2
но это возвращает двойной, я думаю, что нужно привести к длинному?
knocte
30

Будьте осторожны, если вам нужна точность выше миллисекунд!

Методы .NET (v4.6) (например, FromUnixTimeMilliseconds ) не обеспечивают эту точность.

AddSeconds и AddMilliseconds также обрезают микросекунды в два раза.

Эти версии имеют высокую точность:

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;
}
Феликс Кейл
источник
2
Это правильный ответ. Другие получают неправильный часовой пояс при конвертации обратно из метки времени.
IamIC
для DateTime-> Java просто [code] return (long) unixTimeStampInTicks / TimeSpan.TicksPerMilliSecond; [/ code]
Макс
Так что по вашему UnixTimestampToDateTime, поставка unixTimeеще в секундах, верно?
Нгок Фам
@NgocPham да, это так
Феликс Кейл
14

См. 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
источник
Это хорошо, но я бы предложил небольшое изменение: использование типа "long" должно быть изменено на "Int32" или "int". «Длинный» подразумевает, что есть значительная точность, но это не так. Вся математика точна только с точностью до 1 секунды, поэтому Int32 будет более показательным из того, что вы ожидаете от отметки времени Unix
JamesHoux
3
Я думаю, что это из-за DateTime.TicksInt64 (long), поэтому они избегают лишних проверок.
Орад
10

В дополнение к ответу Скоттера, я недавно оказался в неприятном сценарии, когда метки времени UNIX в секундах и миллисекундах произвольно смешиваются во входном наборе данных. Следующий код, кажется, справляется с этим хорошо:

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);
}
Крис Томан
источник
1
Будьте осторожны, когда не используете аргумент DateTimeKind, поскольку созданный DateTime будет находиться по местному времени компьютера (спасибо за код, Крис)!
Сэм Грондаль
1
Осторожно - это не будет работать для меток времени Unix для дат до 11 января 1978 года, если они представлены в миллисекундах. Отметка даты в Unix 253324800 (секунд) дает правильную дату 11.01.1978, а представление в виде миллисекунды 253324800000 - 18.07.9997. Возможно, это сработало для вашего набора данных, но это не общее решение.
Ойвинд
8

Преобразование времени в Unix впервые в .NET Framework 4.6.

Теперь вы можете легко преобразовывать значения даты и времени в типы .NET Framework и время Unix или из них. Это может быть необходимо, например, при преобразовании значений времени между клиентом JavaScript и сервером .NET. Следующие API были добавлены в структуру DateTimeOffset :

static DateTimeOffset FromUnixTimeSeconds(long seconds)
static DateTimeOffset FromUnixTimeMilliseconds(long milliseconds)
long DateTimeOffset.ToUnixTimeSeconds()
long DateTimeOffset.ToUnixTimeMilliseconds()
Фред
источник
Это не дает вам местное время, вы получаете UTC.
Беренд де Бур
@BerenddeBoer Это разумное значение по умолчанию. Вы можете применить пользовательское смещение после этого, как вы хотите.
Дейлан
1
@BerenddeBoer Это неправильно понимает, что такое время Unix. Время Unix - секунды с полуночи, 1 января 1970 года, UTC. Неважно, где вы находитесь, количество секунд с той эпохи не меняется. Преобразование его в удобочитаемые индикации местного времени отделено от этого универсального представления, как и должно быть.
Tanktalus
5

Я нашел правильный ответ, просто сравнив конверсию с 01.01.1970 без учета местного времени;

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
источник
4
var dt = DateTime.Now; 
var unixTime = ((DateTimeOffset)dt).ToUnixTimeSeconds();

// 1510396991

var dt = DateTimeOffset.FromUnixTimeSeconds(1510396991);

// [11.11.2017 10:43:11 +00: 00]

Месут
источник
4

Из .net 4.6 вы можете сделать это:

var dateTime = DateTimeOffset.FromUnixTimeSeconds(unixDateTime).DateTime;
Ян Чжан
источник
3
DateTime unixEpoch = DateTime.ParseExact("1970-01-01", "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture);
DateTime convertedTime = unixEpoch.AddMilliseconds(unixTimeInMillisconds);

Конечно, можно сделать unixEpochглобальный статический элемент, поэтому он должен появиться только один раз в вашем проекте, и его можно использовать, AddSecondsесли время UNIX указано в секундах.

Чтобы пойти другим путем:

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

Обрезать до Int64 и / или использовать по TotalSecondsмере необходимости.

Горячие лижет
источник
3

Написано простейшее расширение, которое работает для нас. Если кто-то ищет это ...

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

        return DateTimeOffset.FromUnixTimeSeconds(long.Parse(unixTimeStamp)).UtcDateTime;
    }
}
Рияз Хамид
источник
2

Тик Unix составляет 1 секунду (если я хорошо помню), а тик .NET - 100 наносекунд.

Если у вас возникли проблемы с наносекундами, вы можете попробовать использовать AddTick (значение 10000000 *).

Luk
источник
3
Unix - это секунды после эпохи, то есть 1/1/70.
ScottCher
1

Мне нужно было преобразовать временную структуру (секунды, микросекунды), содержащую UNIX timeв, DateTimeбез потери точности, и я не нашел здесь ответа, поэтому я подумал, что просто могу добавить свою:

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
источник
1

Вы можете использовать DateTimeOffset .

Например. У меня есть объект DateTime

var dateTime=new DateTime();

Если я хочу преобразовать его в метки времени Unix, я могу достичь следующего

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

Для получения дополнительной информации, пожалуйста, перейдите по этой ссылке: DateTimeOffset.ToUnixTimeSeconds Метод

Рамиль Алиев
источник
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();
        }
    }

Вы можете вызвать UnixTime.UnixTimeToDateTime (double datetime))

Мадан
источник
-2

Для .NET 4.6 и более поздних версий:

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);
    }
}
superlogical
источник
4
Не понимаю. В .NET 4.6 BCL уже имеет эти методы (см., Например, мой комментарий к вышеупомянутому вопросу или некоторые другие новые ответы (2015 г.). Так какой смысл писать их снова? Вы имели в виду, что ваш ответ был решение для версий до 4.6?
Jeppe Stig Nielsen