Làm cách nào tôi có thể chuyển đổi dấu thời gian Unix sang DateTime và ngược lại?


754

Có mã ví dụ này, nhưng sau đó nó bắt đầu nói về các vấn đề mili giây / nano giây.

Câu hỏi tương tự là trên MSDN, Giây kể từ thời kỳ Unix trong C # .

Đây là những gì tôi đã có cho đến nay:

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 sắp ra mắt (sẽ được phát hành vào cuối năm nay) giới thiệu hỗ trợ cho việc này. Xem DateTimeOffset.FromUnixTimeSecondsDateTimeOffset.ToUnixTimeSecondsphương pháp. Có các phương pháp cho mili giây unix-time là tốt.
Jeppe Stig Nielsen

Câu trả lời:


1017

Đây là những gì bạn cần:

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

Hoặc, đối với Java (khác với dấu thời gian tính bằng mili giây chứ không phải giây):

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
Thời gian trong Windows được xử lý bởi HAL và chỉ gần chính xác trong vòng 1ms đến 15ms. Thông tin thêm có sẵn trong Windows Internals xung quanh trang 112, nếu có ai quan tâm.
Jim Schubert

16
Câu trả lời này có nguy cơ cắt ngắn giây ... Một đôi là một số trôi nổi. Đối số nên là int / long / etc.
ccook

44
Các phương thức này nên chấp nhận một dài hoặc int, không phải là một đôi. Ngoài ra, đối với tem thời gian Java, không cần chia 1000 và làm tròn. Chỉ cần làmdtDateTime.AddMilliseconds(javaTimeStamp).ToLocalTime();
Justin Johnson

11
Bạn đã bỏ lỡ "ngược lại"? Làm cách nào để chuyển đổi DateTime thành dấu thời gian?
Jonny

38
Đối với .NET Framework 4.6 trở lên, hiện có static DateTimeOffset.FromUnixMillisecondsDateTimeOffset.ToUnixMilliseconds.
rookie1024

422

Các phiên bản mới nhất của .NET (v4.6) đã bổ sung built-in hỗ trợ cho chuyển đổi thời gian Unix. Điều đó bao gồm cả đến và từ thời gian Unix được biểu thị bằng giây hoặc mili giây.

  • Thời gian Unix tính bằng giây đến UTC DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset đến thời gian Unix tính bằng giây:

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • Thời gian Unix tính bằng mili giây đến UTC DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset đến thời gian Unix tính bằng mili giây:

long unixTimeStampInMilliseconds = dateTimeOffset.ToUnixTimeMilliseconds();

Lưu ý: Các phương thức này chuyển đổi sang và từ một UTC DateTimeOffset. Để có được một DateTimeđại diện chỉ cần sử dụng các thuộc tính DateTimeOffset.UtcDateTimehoặc DateTimeOffset.LocalDateTime:

DateTime dateTime = dateTimeOffset.UtcDateTime;


Điều này không chuyển đổi thời gian sang giờ địa phương. Bạn nhận được UTC nếu bạn sử dụng DateTime Offerset.FromUnixTimeSeconds ().
Berend de Boer

4
@BerenddeBoer Bạn có thể sử dụng ToLocalTimenếu bạn muốn.
i3arnon

1
Để có được thời gian hiện tại, bạn có thể sử dụnglong unixMilliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Dan Diplo

219

Dấu thời gian DateTime đến 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

Từ Wikipedia :

UTC không thay đổi theo sự thay đổi của các mùa, nhưng giờ địa phương hoặc giờ dân sự có thể thay đổi nếu phạm vi quyền hạn theo múi giờ quan sát thời gian tiết kiệm ánh sáng ban ngày (giờ mùa hè). Ví dụ, giờ địa phương ở bờ biển phía đông Hoa Kỳ chậm hơn UTC năm giờ trong mùa đông, nhưng bốn giờ sau khi tiết kiệm ánh sáng ban ngày được quan sát ở đó.

Vì vậy, đây là mã của tôi:

TimeSpan span = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0,DateTimeKind.Utc));
double unixTime = span.TotalSeconds;

2
Nhưng điều này trả lại gấp đôi, tôi đoán người ta cần phải kéo dài?
knocte

30

Hãy cẩn thận, nếu bạn cần độ chính xác cao hơn mili giây!

Các phương thức .NET (v4.6) (ví dụ: FromUnixTimeMilliseconds ) không cung cấp độ chính xác này.

AddSecondsAddMilliseconds cũng cắt giảm micro giây trong gấp đôi.

Các phiên bản này có độ chính xác cao:

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

Ngày giờ -> 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
Đây là câu trả lời chính xác. Những người khác nhận được múi giờ không chính xác trên chuyển đổi trở lại từ dấu thời gian.
IamIC

đối với DateTime-> Java, chỉ cần [code] return (dài) unixTimeStampInTicks / TimeSpan.TicksPerMilliSecond; [/ code]
Tối đa

Vì vậy, trong bạn UnixTimestampToDateTime, cung cấp unixTimevẫn còn trong vài giây, phải không?
Ngọc Phạm

@NgocPham đúng vậy
Felix Keil

14

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

Điều này là tốt, nhưng tôi đề nghị một thay đổi nhỏ: Nên sử dụng loại "dài" thành "Int32" hoặc "int". "Dài" ngụ ý có độ chính xác đáng kể, nhưng không có. Tất cả các phép toán chỉ chính xác đến 1 giây, vì vậy Int32 sẽ gợi ý nhiều hơn về những gì bạn mong đợi từ dấu thời gian Unix
JamesHoux

3
Tôi nghĩ rằng đó là do DateTime.TicksInt64 (dài), vì vậy họ đang tránh một dàn diễn viên không được kiểm tra thêm.
orad

10

Để bổ sung cho câu trả lời của ScottCher, gần đây tôi thấy mình trong kịch bản khó chịu khi có cả hai giây và mili giây Dấu thời gian UNIX được trộn lẫn tùy ý trong một tập dữ liệu đầu vào. Các mã sau đây dường như xử lý tốt điều này:

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
Hãy cẩn thận khi không sử dụng đối số DateTimeKind, vì DateTime được xây dựng sẽ ở trong giờ địa phương của máy tính (cảm ơn mã, Chris)!
Sam Grondahl

1
Coi chừng - điều này sẽ không hoạt động đối với dấu thời gian unix cho các ngày trước ngày 11 tháng 1 năm 1978 nếu chúng được biểu thị bằng mili giây. Một dấu thời gian unix là 25.3324800 (giây) đưa ra ngày chính xác là 11,01.1978, trong khi đại diện mili giây 25.3324800000 đưa ra ngày 18,07.9997. Điều này có thể đã làm việc cho tập dữ liệu của bạn, nhưng nó không phải là một giải pháp chung.
Øyvind

8

Chuyển đổi thời gian Unix là mới trong .NET Framework 4.6.

Bây giờ bạn có thể dễ dàng chuyển đổi giá trị ngày và thời gian sang hoặc từ các loại .NET Framework và thời gian Unix. Điều này có thể cần thiết, ví dụ, khi chuyển đổi giá trị thời gian giữa máy khách JavaScript và máy chủ .NET. Các API sau đã được thêm vào cấu trúc DateTimePackset :

static DateTimeOffset FromUnixTimeSeconds(long seconds)
static DateTimeOffset FromUnixTimeMilliseconds(long milliseconds)
long DateTimeOffset.ToUnixTimeSeconds()
long DateTimeOffset.ToUnixTimeMilliseconds()

Điều này không cung cấp cho bạn giờ địa phương, bạn nhận được UTC.
Berend de Boer

@BerenddeBoer Đó là một mặc định hợp lý. Bạn có thể áp dụng một bù tùy chỉnh sau đó như bạn muốn.
Deilan

1
@BerenddeBoer Điều đó hiểu sai thời gian unix là gì. Thời gian Unix là vài giây kể từ nửa đêm, ngày 1 tháng 1 năm 1970, UTC. Không quan trọng bạn đang ở đâu, số giây kể từ thời điểm đó không thay đổi. Chuyển đổi nó thành hiển thị giờ địa phương có thể đọc được của con người tách biệt với đại diện phổ quát này, như nó phải vậy.
Tanktalus

5

Tôi đã tìm thấy câu trả lời đúng chỉ bằng cách so sánh chuyển đổi với 1/1/1970 w / o điều chỉnh thời gian cục bộ;

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

// 1510394991

var dt = DateTimeOffset.FromUnixTimeSeconds(1510396991);

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


4

Từ .net 4.6, bạn có thể làm điều này:

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

Tất nhiên, người ta có thể tạo unixEpochmột tĩnh toàn cầu, vì vậy nó chỉ cần xuất hiện một lần trong dự án của bạn và người ta có thể sử dụngAddSeconds nếu thời gian UNIX tính bằng giây.

Đi theo con đường khác:

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

Cắt ngắn để Int64 và / hoặc sử dụng TotalSecondskhi cần thiết.


3

Viết một phần mở rộng đơn giản nhất làm việc cho chúng tôi. Nếu bất cứ ai tìm kiếm nó ...

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

        return DateTimeOffset.FromUnixTimeSeconds(long.Parse(unixTimeStamp)).UtcDateTime;
    }
}


2

Một đánh dấu Unix là 1 giây (nếu tôi nhớ rõ) và một đánh dấu .NET là 100 nano giây.

Nếu bạn đã gặp phải sự cố với nano giây, bạn có thể muốn thử sử dụng AddTick (giá trị 10000000 *).


3
Unix là giây qua kỷ nguyên - tức là 1/1/70.
ScottCher

1

Tôi cần thiết để chuyển đổi một struct timeval (giây, micro) có chứa UNIX timetới DateTimemà không làm mất độ chính xác và đã không tìm thấy một câu trả lời ở đây vì vậy tôi nghĩ tôi chỉ có thể thêm vào tôi:

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

Bạn có thể sử dụng DateTime Offerset .

Ví dụ. Tôi có đối tượng DateTime

var dateTime=new DateTime();

Nếu tôi muốn chuyển đổi nó sang tem thời gian Unix, tôi có thể đạt được như sau

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

Để biết thêm thông tin, vui lòng truy cập liên kết này: Phương thức DateTime Offerset.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();
        }
    }

bạn có thể gọi UnixTime.UnixTimeToDateTime (gấp đôi thời gian)


-2

Đối với .NET 4.6 trở lên:

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
Tôi không hiểu. Trong .NET 4.6, BCL đã có các phương thức đó (xem ví dụ: nhận xét của tôi cho câu hỏi ở trên hoặc một số câu trả lời mới khác (2015). Vậy ý nghĩa của việc viết lại chúng là gì? một giải pháp cho các phiên bản trước 4.6?
Jeppe Stig Nielsen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.