Як я можу конвертувати часову позначку Unix в DateTime і навпаки?


754

Цей приклад коду є, але потім він починає говорити про проблеми мілісекунд / наносекунд.

Це ж питання стосується 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методи. Існують також методи для мілісекундного унікс-часу.
Джеппе Стіг Нільсен

Відповіді:


1017

Ось що вам потрібно:

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

5
Час роботи в Windows обробляється HAL і лише близький до точного в межах 1 мс до 15 мс. Більше інформації можна знайти у службі внутрішніх справ Windows на сторінці 112, якщо хтось зацікавлений.
Джим Шуберт

16
Ця відповідь ризикує обрізати секунди ... Подвійний - це плаваюче число. Аргумент повинен бути int / long / тощо.
ccook

44
Ці методи повинні приймати довгий або int, а не подвійний. Крім того, для часових позначок Java не потрібно ділити на 1000 і круглих. Просто зробітьdtDateTime.AddMilliseconds(javaTimeStamp).ToLocalTime();
Джастін Джонсон

11
Ви просто пропустили "навпаки"? Як перетворити DateTime у часову позначку?
Джоні

38
Для .NET Framework 4.6 і вище існує зараз static DateTimeOffset.FromUnixMillisecondsі DateTimeOffset.ToUnixMilliseconds.
rookie1024

421

Остання версія .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;


Це не перетворює час на місцевий час. Ви отримуєте UTC, якщо використовуєте DateTimeOffset.FromUnixTimeSeconds ().
Беренд де Бур

4
@BerenddeBoer Ви можете використовувати, ToLocalTimeякщо хочете.
i3arnon

1
Щоб отримати поточний час, ви можете скористатисьlong unixMilliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Dan Diplo

219

ДатаTime до часової позначки 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;

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, просто [код] повернути (довгий) unixTimeStampInTicks / TimeSpan.TicksPerMilliSecond; [/ код]
Макс

Тож у вашому 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);
    }
}

Це добре, але я б запропонував невелику зміну: використання типу "long" слід змінити на "Int32" або "int". "Довгий" означає, що є значна точність, але немає. Вся математика точна лише до 1 секунди, тому Int32 буде більше
підказувати,

3
Я думаю, що це пов'язано з DateTime.Ticksтим, що це Int64 (тривалий), тому вони уникають зайвої неперевіреної ролі.
orad

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 року, якщо вони представлені в мілісекундах. Універсальна мітка дати 253324800 (секунд) дає правильну дату 11.01.1978 р., Тоді як представлення мілісекунд 253324800000 дає 18.07.9997 р. Це, можливо, спрацювало для вашого набору даних, але це не загальне рішення.
Øyvind

8

Перетворення часу Unix є новим у .NET Framework 4.6.

Тепер ви можете легше конвертувати значення дати та часу у типи .NET Framework або з них. Це може знадобитися, наприклад, при перетворенні значень часу між клієнтом JavaScript і сервером .NET. У структуру DateTimeOffset додано такі API :

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

Я знайшов правильну відповідь, лише порівнявши перетворення на 1/1/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;

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 *).


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

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 (подвійний час)


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

4
Я не розумію. У .NET 4.6 BCL вже має ці методи (див., Наприклад, мій коментар до вищезазначеного питання або деякі інші нові відповіді (2015 р.). Тож, у чому полягає сенс у їх написанні ще раз? Ви мали на увазі, що ваша відповідь була рішення для версій до 4.6?
Jeppe Стіг Нільсен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.