Bagaimana Anda mengonversi waktu zaman dalam C #?

377

Bagaimana Anda mengubah waktu Unix ke waktu nyata dalam C #? (Epoch awal 1/1/1970)

hwhterwhite
sumber
1
Kecuali saya kehilangan sesuatu, "zaman" hanyalah titik awal dari skema ketepatan waktu tertentu. Contohnya termasuk 1/1/0001, 1/1/1970 dan 1/1/2000. Ini lebih merupakan atribut dari skema daripada skema (misalnya, Julian) itu sendiri.
Bob Kaufman
8
Waktu sejak zaman adalah jumlah detik sejak 1 Januari 1970 UTC.
Taylor Leese
13
@Aylor Itu zaman untuk waktu unix, dan itu mungkin benar, tapi itu bukan satu-satunya zaman yang valid. Pengguna unix waktu tidak boleh membingungkan diri sendiri tentang hal itu.
Joel Coehoorn
Dup, dengan jawaban lain: stackoverflow.com/q/3354893/712526
jpaugh

Jawaban:

563

Saya kira maksud Anda waktu Unix , yang didefinisikan sebagai jumlah detik sejak tengah malam (UTC) pada tanggal 1 Januari 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
sumber
74
Agar ini berfungsi dengan benar, saya harus mengubah .AddSeconds menjadi .AddMilliseconds. Anda perlu mengetahui apakah nomor Anda berasal dari Detik atau Milidetik untuk mendapatkan hasil yang benar. Jadi misalnya tanggal berikut: 1406310305188 (25 Juli 2014). epochconverter.com juga akan memungkinkan Anda memeriksa hasil konversi Anda.
jrandomuser
5
Anda harus mengubah tipe parameter menjadi dua kali lipat (karena AddSeconds menerima ganda dan karenanya akan turun ke ganda) atau menambahkan penafian ke deskripsi metode bahwa hanya 53 dari 64 bit presisi dalam argumen akan dipertahankan.
Tomosius
6
@jrandomuser: Waktu era Unix secara tradisional direpresentasikan sebagai detik sejak The Epoch. Sejak menjadi umum untuk menggunakan milidetik sejak The Epoch (misalnya, JavaScript), tetapi definisi klasiknya adalah detik. Intinya, ketahui saja nilai input Anda (detik, milidetik, kutu, apa pun) dan gunakan AddXYZmetode yang tepat .
TJ Crowder
Pertama coba dengan AddMilliseconds dan jika tahun masih 1970 maka lakukan AddSeconds. Dengan cara ini ia akan bekerja sepanjang waktu tanpa harus khawatir tentang milidetik atau detik. Plus, Anda dapat mencegah pengecualian melimpah. Melewati sejumlah besar ke AddSeconds akan membuat kode macet
Tono Nam
213

Versi terbaru .Net (v4.6) baru saja menambahkan dukungan bawaan untuk konversi waktu Unix. Itu termasuk ke dan dari waktu Unix yang diwakili oleh detik atau milidetik.

  • Unix waktu dalam detik ke DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset ke waktu Unix dalam detik:

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • Unix waktu dalam milidetik ke DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset hingga waktu Unix dalam milidetik:

long unixTimeStampInMilliseconds= dateTimeOffset.ToUnixTimeMilliseconds();

Catatan: Metode ini dikonversi ke dan dari DateTimeOffset. Untuk mendapatkan DateTimerepresentasi cukup gunakan DateTimeOffset.DateTimeproperti:

DateTime dateTime = dateTimeOffset.UtcDateTime;
i3arnon
sumber
1
Saya mendapatkan 'DateTimeOffset' does not contain a definition for 'FromUnixTimeSeconds'Bagaimana saya bisa menyelesaikan ini?
Happy Bird
@ HappyBird Apakah Anda menggunakan .NET 4.6 atau lebih tinggi?
i3arnon
Hal yang sama - 4.7.2 dan tidak memiliki metode FromUnixTimeMilliseconds untuk DateTimeOffset ...
Mikhail_Sam
Saya mendapatkannya. Saya tidak perlu membuat objek baru. Ini metode statis.
Mikhail_Sam
Saya menemukan nilai default sedikit membingungkan pada pandangan pertama. Bc 1000 adalah faktor untuk mengkonversi dari mil ke detik.
BluE
169

Dengan semua kredit untuk LukeH, saya telah mengumpulkan beberapa metode ekstensi untuk mudah digunakan:

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

Perhatikan komentar di bawah dari CodesInChaos bahwa di atas FromUnixTimekembali sebuah DateTimedengan Kinddari Utcyang baik-baik saja, tetapi di atas ToUnixTimejauh lebih tersangka dalam yang tidak memperhitungkan apa DateTimeMengingat dateadalah. Untuk memungkinkan date's Kindmakhluk baik Utcatau Local, penggunaan 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);
}

ToUniversalTimeakan mengonversi Local(atau Unspecified) DateTimeke Utc.

jika Anda tidak ingin membuat contoh DateTime zaman ketika pindah dari DateTime ke zaman Anda juga dapat melakukan:

public static long ToUnixTime(this DateTime date)
{
    return (date.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
}
Ben Cull
sumber
6
ToUnixTimehanya berfungsi dengan benar jika tanggal dalam Utc. Tambahkan cek, atau ubah. (Secara pribadi saya lebih suka cek)
CodesInChaos
2
Hanya menghabiskan satu jam terakhir mencari tahu mengapa ini tidak berhasil. Anda perlu bekerja di milliseconds tidak detik !!!
KristianB
7
@KristianB: "Waktu Unix" secara tradisional adalah detik, bukan milidetik, sejak The Epoch, meskipun hari ini saya berhati-hati untuk memeriksa definisi apa yang digunakan seseorang. Detik dulunya cukup baik, dan memberi kami rentang yang wajar dari kedua sisi Epoch dalam nilai 32-bit yang ditandatangani. (Dan itulah sebabnya setelah jam 3:14 pada tanggal 19 Januari, 2038 GMT mungkin waktu yang buruk untuk beberapa ...) Menggunakan milidetik adalah praktik yang lebih modern berkat secara rutin kami mampu memberikan nilai 64-bit (keduanya integral) dan presisi ganda IEEE-754) ...
TJ Crowder
5
Terima kasih untuk kodenya. Hanya sedikit rekomendasi saat membuat basis Epoch: pastikan untuk secara eksplisit menetapkan nilai Milidetik ke 0. yaitu var epoch = DateTime baru (1970, 1, 1, 0 / * h * /, 0 / * m * /, 0 / * s * /, 0 / * ms * /, DateTimeKind.Utc); Jika Anda tidak menetapkannya secara eksplisit, nilai milidetik tampaknya keluar sebagai 1. Ini menyebabkan beberapa inkonsistensi dalam pengujian saya.
ctrlplusb
1
Anda harus menggunakan AddMillisecondsdan Anda harus menggunakan Double NOT Float. Kalau tidak, Anda akan berakhir dengan waktu yang salah.
Axel
25

Anda sebenarnya ingin AddMilliseconds (milidetik), bukan detik. Menambahkan detik akan memberi Anda pengecualian di luar rentang.

Darya
sumber
Mengapa demikian? epochconverter.com Dikatakan Anda menambahkan jumlah detik sejak 1/1/970 bukan ms.
Jamie R Rytlewski
Jika Anda pergi dari ms Anda jelas ingin AddMillisdan jika Anda mulai dari detik Anda jelas ingin AddSeconds.
Sepatu
Saya memiliki masalah yang sama ketika saya terus keluar dari jangkauan ketika menggunakan detik. Waktu unix yang saya coba konversi adalah dalam milidetik. Saya pikir itu dalam hitungan detik. Saya kira beberapa waktu unix diukur dalam milidetik.
DoodleKana
Waktu Unix biasanya dinyatakan dalam detik, tetapi 0,001 adalah jumlah detik yang valid (= 1 ms). Jika ragu, gunakan presisi setinggi mungkin.
Scott
9

Jika Anda menginginkan kinerja yang lebih baik, Anda dapat menggunakan versi ini.

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

Dari patokan cepat (BenchmarkDotNet) di bawah net471 saya mendapatkan nomor ini:

        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 |

2x lebih cepat dari versi LukeH (jika kinerja mater)

Ini mirip dengan bagaimana DateTime bekerja secara internal.

Jiri Sykora
sumber
9

Gunakan metode DateTimeOffset.ToUnixTimeMilliseconds () Ini mengembalikan jumlah milidetik yang telah berlalu sejak 1970-01-01T00: 00: 00.000Z.

Ini hanya didukung dengan Kerangka 4.6 atau lebih tinggi

var EPOCH = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

Ini didokumentasikan dengan baik di sini DateTimeOffset.ToUnixTimeMilliseconds

Cara keluar lainnya adalah menggunakan yang berikut ini

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

Untuk mendapatkan EPOCH hanya dalam hitungan detik Anda dapat menggunakan

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

dan konversikan Epochke DateTimedengan metode berikut

private DateTime Epoch2UTCNow(int epoch) 
{
    return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(epoch); 
}
Vinod Srivastav
sumber
DateTime.Ticks - setiap centang adalah "seratus nanodetik", menjadikannya 'hal' tambahan untuk diingat. Jika menghilangkan keduanya .Ticks, orang akan mendapatkan contoh TimeSpan yang bagus dari subtitle 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);
}

Harus menggunakan ToUniversalTime () untuk objek DateTime.

Green Su
sumber
5

Saya menggunakan metode ekstensi berikut untuk konversi zaman

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
sumber
2

Untuk tidak khawatir menggunakan milidetik atau detik, lakukan saja:

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

Jika waktu dalam detik, maka tidak mungkin Anda bisa melewati tahun 1972 dengan menambahkan milidetik.

Tono Nam
sumber
1

Jika Anda tidak menggunakan 4.6, ini dapat membantu Sumber: 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;
    }    
Siva Kandaraj
sumber
Terima kasih misalnya dari JWT. Ngomong-ngomong, untuk menggunakannya, cukup gunakan: using Microsoft.IdentityModel.Tokens; ... EpochTime.GetIntDate(dateTime);
liquidide
0

Dalam kasus Anda perlu mengkonversi struct timeval (detik, mikrodetik) mengandung UNIX timeke DateTimetanpa kehilangan presisi, ini adalah bagaimana:

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
sumber
0

Sejak .Net 4.6 dan di atasnya, gunakan DateTimeOffset.Now.ToUnixTimeSeconds ()

Saikat Chakraborty
sumber
-4

Inilah solusi saya:

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);
}
sandeep
sumber
7
apakah akun ini untuk tahun kabisat dan detik kabisat dll?
Jodrell
1
Untuk memperluas komentar sebelumnya, berikut adalah video singkat yang menjelaskan mengapa waktu itu rumit dan mengapa Anda tidak boleh mencoba melakukannya sendiri: youtube.com/watch?v=-5wpm-gesOY
vmrob