Как вы конвертируете время эпохи в C #?

377

Как конвертировать время эпохи Unix в C # в реальном времени? (Начало эпохи 01.01.1970)

hsatterwhite
источник
1
Если я что-то упустил, «эпоха» - это просто точка начала конкретной схемы хронометража. Примеры включают 1/1/0001, 01.01.1970 и 01.01.2000. Это скорее атрибут схемы, нежели сама схема (например, Джулиан).
Боб Кауфман
8
Время с начала эпохи - это количество секунд с 1 января 1970 года по Гринвичу.
Тейлор Лиз
13
@Taylor Это эпоха для времени Unix, и это, вероятно, правильно, но это не единственная действительная эпоха. Пользователи времени Unix не должны путать себя в этом вопросе.
Джоэл Коухорн
Дуп, с другими ответами: stackoverflow.com/q/3354893/712526
jpaugh

Ответы:

563

Я предполагаю, что вы имеете в виду время Unix , которое определяется как количество секунд с полуночи (UTC) 1 января 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
источник
74
Чтобы заставить это работать правильно, я должен был изменить .AddSeconds на .AddMilliseconds. Вам нужно будет узнать, исходит ли ваш номер в секундах или миллисекундах, чтобы получить правильный результат. Так, например, следующая дата: 1406310305188 (25 июля 2014 г.). epochconverter.com также позволит вам проверить результаты конверсии.
jrandomuser
5
Вам следует либо изменить тип параметра на double (поскольку AddSeconds принимает значение double и, следовательно, будет уменьшен до удвоения), либо добавить в описание метода отказ от ответственности, что в аргументе будет сохранена только 53 из 64 бит точности.
Томосий
6
@jrandomuser: время эпохи Unix традиционно представляется в секундах с начала эпохи. С тех пор стало обычным использование миллисекунд со времен The Epoch (например, JavaScript), но классическое определение - секунды. Итог, просто знайте, каково ваше входное значение (секунды, миллисекунды, тики, что угодно) и используйте правильный AddXYZметод.
TJ Crowder
Сначала попробуйте с AddMilliseconds, и если год все еще 1970, тогда сделайте AddSeconds. Таким образом, он будет работать все время, не беспокоясь о миллисекундах или секундах. Плюс вы можете предотвратить исключение переполнения. Передача большого числа в AddSeconds приведет к сбою кода
Nam
213

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

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

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

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

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

long unixTimeStampInMilliseconds= dateTimeOffset.ToUnixTimeMilliseconds();

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

DateTime dateTime = dateTimeOffset.UtcDateTime;
i3arnon
источник
1
Я получаю 'DateTimeOffset' does not contain a definition for 'FromUnixTimeSeconds'Как бы я решить эту проблему?
Счастливая птица
@HappyBird Вы на .NET 4.6 или выше?
i3arnon
То же самое - 4.7.2 и не имеют метода FromUnixTimeMilliseconds для DateTimeOffset ...
Mikhail_Sam
Я понял. Мне не нужно создавать новый объект. Это статический метод.
Mikhail_Sam
На мой взгляд, значения по умолчанию немного смущают на первый взгляд. Bc 1000 - это коэффициент для перевода из миллисекунд в секунды.
BluE
169

С благодарностью LukeH я собрал несколько методов расширения для легкого использования:

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

Обратите внимание на комментарий ниже от CodesInChaos , что выше FromUnixTimeвозвращает DateTimeс Kindиз Utc, что это хорошо, но выше ToUnixTimeгораздо больше подозрений в том , что не учитывает , какого рода DateTimeданного dateесть. Для того, чтобы обеспечить date«S Kindбытия либо Utcили Local, используйте 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);
}

ToUniversalTimeпреобразует Local(или Unspecified) DateTimeв Utc.

если вы не хотите создавать экземпляр DateTime эпохи при переходе от DateTime к эпохе, вы также можете сделать следующее:

public static long ToUnixTime(this DateTime date)
{
    return (date.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
}
Бен Калл
источник
6
ToUnixTimeработает правильно только если дата в Utc. Либо добавьте чек, либо конвертируйте его. (Лично я предпочитаю чек)
CodesInChaos
2
Просто провел последний час, выясняя, почему это не работает. Вы должны работать в milliseconds не секунды !!!
KristianB
7
@KristianB: «Время Unix» - это традиционно секунды, а не миллисекунды со времен The Epoch, хотя в эти дни я тщательно проверяю, какое определение кто-то использует. Секунды раньше были достаточно хорошими и давали нам разумный диапазон по обе стороны от Epoch в знаковых 32-битных значениях. (И именно поэтому сразу после 3:14 утра 19 января 2038 года по Гринвичу для некоторых может наступить плохое время ...) Использование миллисекунд является более современной практикой благодаря нашей обычной способности выбрасывать 64-битные значения (оба являются целыми и двойной точности IEEE-754) ...
TJ Crowder
5
Спасибо за код. Просто небольшая рекомендация при создании базы Epoch: обязательно установите значение Millisecond равным 0. т.е. var epoch = new DateTime (1970, 1, 1, 0 / * h * /, 0 / * m * /, 0 / * s * /, 0 / * мс * /, DateTimeKind.Utc); Если вы не укажете явно, значение в миллисекундах будет равно 1. Это вызвало некоторые несоответствия в моих тестах.
ctrlplusb
1
Вы должны использовать, AddMillisecondsи вы должны использовать Double NOT Float. В противном случае у вас будет неправильное время.
Аксель
25

Вы действительно хотите добавить миллисекунды (миллисекунды), а не секунды. Добавление секунд даст вам исключение вне диапазона.

Дарья
источник
Это почему? epochconverter.com Это говорит о том, что вы добавляете количество секунд, так как 1/1/970 не мс.
Джейми Р Ритлевски
Если вы идете от мс, вы, очевидно, хотите, AddMillisи если вы начинаете с секунд, вы, очевидно, хотите AddSeconds.
Чистка
У меня была та же проблема, что я продолжал выходить за пределы диапазона при использовании секунд. Время Unix, которое я пытался преобразовать, было в миллисекундах. Я думал, что это было в считанные секунды. Я предполагаю, что некоторое время Unix измеряется в миллисекундах.
DoodleKana
Время Unix обычно выражается в секундах, но 0,001 - это допустимое количество секунд (= 1 мс). В случае сомнений просто используйте максимально возможную точность.
Скотт
9

Если вы хотите лучшую производительность, вы можете использовать эту версию.

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

Из быстрого теста (BenchmarkDotNet) под net471 я получаю этот номер:

        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 раза быстрее по сравнению с версией LukeH (если производительность зависит)

Это похоже на внутреннюю работу DateTime.

Иржи Сикора
источник
9

Используйте метод DateTimeOffset.ToUnixTimeMilliseconds (). Возвращает количество миллисекунд, прошедших с 1970-01-01T00: 00: 00.000Z.

Это поддерживается только в Framework 4.6 или выше

var EPOCH = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

Это хорошо задокументировано здесь DateTimeOffset.ToUnixTimeMilliseconds

Другим выходом является использование следующего

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

Чтобы получить EPOCH только за секунды, вы можете использовать

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

и преобразовать Epochв DateTimeследующий метод

private DateTime Epoch2UTCNow(int epoch) 
{
    return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(epoch); 
}
Винод Шривастав
источник
DateTime.Ticks - каждый тик составляет «сто наносекунд», что делает его дополнительной «вещью» для запоминания. Если опустить оба .Ticks, можно получить хороший экземпляр TimeSpan из вычитания 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);
}

Следует использовать ToUniversalTime () для объекта DateTime.

Зеленый Су
источник
5

Я использую следующие методы расширения для преобразования эпох

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

Чтобы не беспокоиться об использовании миллисекунд или секунд, просто сделайте:

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

Если время эпохи указано в секундах, вы не сможете пройти 1972 год, прибавив миллисекунды.

Тоно Нам
источник
1

Если вы не используете 4.6, это может помочь 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;
    }    
Шива Кандарадж
источник
Спасибо, например, от JWT. Кстати, использовать его, просто использовать: using Microsoft.IdentityModel.Tokens; ... EpochTime.GetIntDate(dateTime);
Liquide
0

Если вам нужно преобразовать временную структуру (секунды, микросекунды), содержащую 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
источник
0

Начиная с версии .Net 4.6 и выше, используйте DateTimeOffset.Now.ToUnixTimeSeconds ()

Сайкат Чакраборты
источник
-4

Вот мое решение:

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
это учитывает високосные годы и високосные секунды и т. д.?
Джодрелл
1
Чтобы расширить предыдущий комментарий, вот короткое видео, которое объясняет, почему время сложное и почему вы не должны пытаться делать это самостоятельно: youtube.com/watch?v=-5wpm-gesOY
vmrob