Як ви конвертуєте епоху в C #?


377

Як ви перетворюєте час епохи Unix в реальний час у C #? (Початок епохи 1.01.1970)


1
Якщо я чогось не пропускаю, "епоха" - це просто точка виникнення певної схеми хронометражу. Приклади включають 1/1/0001, 1/1/1970 та 1/1/2000. Це скоріше атрибут схеми, а не схема (наприклад, Джуліана).
Боб Кауфман

8
Час з епохи - це кількість секунд з 1 січня 1970 року за UTC.
Тейлор Ліз

13
@Taylor Це епоха для Unix часу, і це, мабуть, правильно, але це не єдина дійсна епоха. Користувачі Unix time не повинні плутати себе з цього приводу.
Джоел Куехорн

Dup з іншими відповідями: 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);

74
Щоб правильно працювати, мені довелося змінити .AddSeconds на .AddMilliseconds. Вам потрібно буде знати, чи походить ваш номер із секунд або мілісекунд, щоб отримати правильний результат. Наприклад, наступна дата: 1406310305188 (25 липня 2014 р.). epochconverter.com також дозволить перевірити результати конверсії.
jrandomuser

5
Вам слід або змінити тип параметра на подвійний (тому що AddSeconds приймає подвійний і, таким чином, знизиться до подвоєного), або додати застереження до опису методу, що лише 53 з 64 біт точності в аргументі будуть збережені.
Томосій

6
@jrandomuser: Епохальний час Unix традиційно представляється секундами з часів епохи. З тих пір стало загальним використання мілісекунд після Epoch (наприклад, JavaScript), але класичне визначення - це секунди. Підсумок, просто знайте, яке ваше вхідне значення (секунди, мілісекунди, тики, що завгодно) та використовуйте правильний AddXYZметод.
TJ Crowder

Спочатку спробуйте з AddMilliseconds, і якщо рік все ще 1970, то зробіть AddSeconds. Таким чином він буде працювати весь час, не турбуючись про мілісекунди чи секунди. Крім того, ви можете запобігти виключення переповнення. Передача великої кількості в AddSeconds призведе до краху коду
Tono 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;

1
Я отримую 'DateTimeOffset' does not contain a definition for 'FromUnixTimeSeconds'Як я б міг вирішити це?
Happy Bird

@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 не за секунди !!!
КрістіанB

7
@ KristianB: "Час Unix" - це традиційно секунди, а не мілісекунди, починаючи з епохи, хоча в ці дні я ретельно перевіряю, яке визначення хтось використовує. Секунди були досить хорошими, і дали нам розумний діапазон в обидві сторони Епохи за підписаними 32-бітовими значеннями. (І тому лише після 3:14 ранку 19 січня 2038 року GMT може бути поганим часом для деяких ...) Використання мілісекунд є більш сучасною практикою завдяки тому, що ми можемо регулярно перекидати 64-бітні значення (обидва цілі і подвійна точність IEEE-754) ...
TJ Crowder

5
Дякуємо за код. Лише невелика рекомендація при створенні бази Epoch: не забудьте чітко встановити значення Millisecond на 0, тобто var epoch = new DateTime (1970, 1, 1, 0 / * h * /, 0 / * m * /, 0 / * s * /, 0 / * ms * /, DateTimeKind.Utc); Якщо ви чітко не встановите це, значення мілісекунд здається рівним 1. Це спричинило деякі невідповідності в моїх тестах.
ctrlplusb

1
Ви повинні використовувати, AddMillisecondsі ви повинні використовувати Double NOT Float. Інакше ви закінчитеся не в той час.
Аксель

25

Ви насправді хочете Додати AddMilliseconds (мілісекунд), а не секунди. Додавання секунд призведе до виключення поза діапазоном.


Чому так? epochconverter.com В ньому йдеться про те, що ви додасте кількість секунд з часу 1/1/970 не мс.
Jamie R Rytlewski

Якщо ви переходите від мс, ви очевидно хочете, 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.

Це підтримується лише Рамкою 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.
користувач2864740

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

    }

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, це може допомогти Джерело: 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);
}


-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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.