Làm thế nào để bạn chuyển đổi thời gian kỷ nguyên trong C #?


377

Làm thế nào để bạn chuyển đổi thời gian epoch Unix thành thời gian thực trong C #? (Kỷ nguyên bắt đầu 1/1/1970)


1
Trừ khi tôi thiếu một cái gì đó, "kỷ nguyên" chỉ đơn giản là điểm gốc của sơ đồ chấm công cụ thể. Ví dụ bao gồm 1/1/0001, 1/1/1970 và 1/1/2000. Đó là nhiều hơn một thuộc tính của một lược đồ chứ không phải là một lược đồ (ví dụ, Julian).
Bob Kaufman

8
Thời gian kể từ kỷ nguyên là số giây kể từ ngày 1 tháng 1 năm 1970 UTC.
Taylor Leese

13
@Taylor Đó là kỷ nguyên cho thời gian unix và có lẽ đúng, nhưng đó không phải là kỷ nguyên hợp lệ duy nhất. Người dùng thời gian Unix không nên nhầm lẫn về điểm đó.
Joel Coehoorn

Dup, với các câu trả lời khác: stackoverflow.com/q/3354893/712526
jpaugh

Câu trả lời:


563

Tôi đoán rằng bạn có nghĩa là thời gian Unix , được định nghĩa là số giây kể từ nửa đêm (UTC) vào ngày 1 tháng 1 năm 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
Để làm cho điều này hoạt động chính xác, tôi đã phải thay đổi .AddSeconds thành .AddMilliseconds. Bạn sẽ cần biết liệu số của bạn đến từ Giây hay Mili giây để có kết quả chính xác. Vì vậy, ví dụ ngày sau: 1406310305188 (ngày 25 tháng 7 năm 2014). epochconverter.com cũng sẽ cho phép bạn kiểm tra kết quả chuyển đổi của mình.
jrandomuser

5
Bạn nên thay đổi loại tham số thành gấp đôi (vì AddSeconds chấp nhận gấp đôi và do đó sẽ giảm xuống gấp đôi) hoặc thêm từ chối trách nhiệm vào mô tả phương thức chỉ có 53 trong số 64 bit chính xác trong đối số sẽ được giữ nguyên.
tomosius

6
@jrandomuser: Thời gian epoch Unix theo truyền thống được biểu thị bằng giây kể từ Epoch. Kể từ đó trở nên phổ biến để sử dụng mili giây kể từ Epoch (ví dụ: JavaScript), nhưng định nghĩa cổ điển là giây. Tóm lại, chỉ cần biết giá trị đầu vào của bạn là gì (giây, mili giây, tích tắc, bất cứ điều gì) và sử dụng đúng AddXYZphương pháp.
TJ Crowder

Lần đầu tiên thử với AddMilliseconds và nếu năm vẫn là 1970 thì hãy thực hiện AddSeconds. Bằng cách này, nó sẽ hoạt động mọi lúc mà không phải lo lắng về mili giây hay giây. Thêm vào đó bạn có thể ngăn chặn một sự bài tiết tràn. Truyền một số lượng lớn vào AddSeconds sẽ khiến mã bị sập
Tono Nam

213

Các phiên bản mới nhất của Net (v4.6) chỉ thêm vào 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 để 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 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ừ DateTimeOffset. Để có được một DateTimeđại diện chỉ cần sử dụng DateTimeOffset.DateTimetài sản:

DateTime dateTime = dateTimeOffset.UtcDateTime;

1
Tôi nhận được 'DateTimeOffset' does not contain a definition for 'FromUnixTimeSeconds'Làm thế nào tôi sẽ giải quyết vấn đề này?
Chim hạnh phúc

@HappyBird Bạn có trên .NET 4.6 trở lên không?
i3arnon

Điều tương tự - 4.7.2 và không có phương thức FromUnixTimeMilliseconds cho DateTime
Offerset

Tôi hiểu rồi. Tôi không cần tạo đối tượng mới. Đó là một phương pháp tĩnh.
Mikhail_Sam

Tôi thấy các giá trị mặc định hơi khó hiểu ngay từ cái nhìn đầu tiên. Bc 1000 là yếu tố để chuyển đổi từ millis sang giây.
BluE

169

Với tất cả tín dụng cho LukeH, tôi đã kết hợp một số phương thức mở rộng để dễ sử dụng:

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

Lưu ý những nhận xét dưới đây từ CodesInChaos rằng ở trên FromUnixTimelợi nhuận một DateTimevới một Kindsố Utc, đó là tốt, nhưng ở trên ToUnixTimelà nhiều nghi ngờ trong đó không tính đến những loại DateTimeGIVEN datelà. Để cho phép datecủa Kindcon người trong hai Utchoặc Local, sử dụng 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);
}

ToUniversalTimesẽ chuyển đổi một Local(hoặc Unspecified) DateTimethành Utc.

nếu bạn không muốn tạo phiên bản DateTime epoch khi chuyển từ DateTime sang epoch, bạn cũng có thể thực hiện:

public static long ToUnixTime(this DateTime date)
{
    return (date.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
}

6
ToUnixTimechỉ hoạt động chính xác nếu ngày ở Utc. Hoặc thêm một kiểm tra, hoặc chuyển đổi nó. (Cá nhân tôi thích kiểm tra hơn)
CodeInChaos

2
Chỉ cần dành một giờ qua để tìm hiểu tại sao điều này không hoạt động. Bạn cần phải làm việc trong milliseconds không vài giây !!!
KristianB

7
@KristianB: "Thời gian Unix" theo truyền thống là giây, không phải mili giây, kể từ Kỷ nguyên, mặc dù những ngày này tôi cẩn thận kiểm tra định nghĩa ai đó đang sử dụng. Giây được sử dụng là đủ tốt và cung cấp cho chúng tôi phạm vi hợp lý ở cả hai phía của Kỷ nguyên trong các giá trị 32 bit đã ký. (Và đó là lý do tại sao chỉ sau 3:14 sáng ngày 19 tháng 1 năm 2038 GMT có thể là thời điểm tồi tệ đối với một số ...) Sử dụng mili giây là một cách thực hành hiện đại hơn nhờ chúng ta thường xuyên có thể ném các giá trị 64 bit (cả hai tích phân và độ chính xác kép của IEEE-754) ...
TJ Crowder

5
Cảm ơn mã. Chỉ là một đề xuất nhỏ khi tạo cơ sở Epoch: đảm bảo đặt rõ ràng giá trị Millisecond thành 0. tức là var epoch = new DateTime (1970, 1, 1, 0 / * h * /, 0 / * m * /, 0 / * s * /, 0 / * ms * /, DateTimeKind.Utc); Nếu bạn không đặt nó một cách rõ ràng, giá trị mili giây dường như xuất hiện là 1. Điều này gây ra một số mâu thuẫn trong các thử nghiệm của tôi.
ctrlplusb

1
Bạn nên sử dụng AddMillisecondsvà bạn nên sử dụng Double NOT Float. Nếu không, bạn sẽ kết thúc với một thời gian sai.
Axel

25

Bạn thực sự muốn AddMilliseconds (mili giây), không phải giây. Thêm giây sẽ cho bạn một ngoại lệ ngoài phạm vi.


Tại sao vậy? epochconverter.com Nó cho biết bạn thêm vào số giây kể từ 1/1/970 chứ không phải ms.
Jamie R Ryussywski

Nếu bạn đang đi từ ms bạn muốn rõ ràng AddMillisvà nếu bạn đang bắt đầu từ giây bạn muốn rõ ràng AddSeconds.
Giày

Tôi gặp vấn đề tương tự tôi đã tiếp tục ra khỏi phạm vi khi sử dụng giây. Thời gian unix tôi đang cố gắng chuyển đổi là tính bằng mili giây. Tôi nghĩ rằng nó là trong vài giây. Tôi đoán một số thời gian unix được đo bằng milisecond.
DoodleKana

Thời gian Unix thường được biểu thị bằng giây, nhưng 0,001 là số giây hợp lệ (= 1 ms). Khi nghi ngờ, chỉ cần sử dụng độ chính xác tối đa có thể.
Scott

9

Nếu bạn muốn hiệu suất tốt hơn, bạn có thể sử dụng phiên bản này.

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

Từ điểm chuẩn nhanh (BenchmarkDotNet) trong net471 tôi nhận được số này:

        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 |

Nhanh hơn gấp 2 lần so với phiên bản của LukeH (nếu phương tiện hiệu suất)

Điều này tương tự như cách hoạt động của DateTime trong nội bộ.


9

Sử dụng phương thức DateTime Offerset.ToUnixTimeMilliseconds () Nó trả về số mili giây đã trôi qua kể từ 1970-01-01T00: 00: 00.000Z.

Điều này chỉ được hỗ trợ với Khung 4.6 trở lên

var EPOCH = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

Nó cũng được ghi lại ở đây DateTime Offerset.ToUnixTimeMilliseconds

Cách khác là sử dụng như sau

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

Để nhận EPOCH chỉ trong vài giây, bạn chỉ có thể sử dụng

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

và chuyển đổi Epochsang DateTimephương thức sau

private DateTime Epoch2UTCNow(int epoch) 
{
    return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(epoch); 
}

DateTime.Ticks - mỗi đánh dấu là "một trăm nano giây", làm cho nó trở thành một 'điều' cần nhớ thêm. Nếu bỏ qua cả hai .Ticks, người ta sẽ lấy lại một cá thể TimeSpan đẹp từ cơ chế DateTime.
dùng2864740

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

Nên sử dụng ToUniversalTime () cho đối tượng DateTime.


5

Tôi sử dụng các phương thức mở rộng sau đây để chuyển đổi kỷ nguyên

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

Để không lo lắng về việc sử dụng mili giây hoặc giây chỉ cần làm:

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

Nếu thời gian kỷ nguyên tính bằng giây thì không có cách nào bạn có thể vượt qua năm 1972 thêm mili giây.


1

Nếu bạn không sử dụng 4.6, điều này có thể giúp Nguồn: 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;
    }    

Cảm ơn ví dụ từ JWT. Bằng cách này, để sử dụng nó, chỉ cần sử dụng: using Microsoft.IdentityModel.Tokens; ... EpochTime.GetIntDate(dateTime);
liquide

0

Trong trường hợp bạn cần phải 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, đây là cách làm:

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

Đây là giải pháp của tôi:

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
tài khoản này cho năm nhuận và giây nhuận vv?
Jodrell

1
Để mở rộng nhận xét trước đây, đây là một video ngắn giải thích tại sao thời gian lại phức tạp và tại sao bạn không nên tự mình làm điều đó: youtube.com/watch?v=-5wpm-gesOY
vmrob
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.