Bagaimana saya bisa mengubah cap waktu Unix ke DateTime dan sebaliknya?

754

Ada contoh kode ini, tetapi kemudian mulai berbicara tentang masalah milidetik / nanodetik.

Pertanyaan yang sama ada di MSDN, Detik sejak zaman Unix di C # .

Inilah yang saya dapatkan sejauh ini:

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);
  }
}
Tandai Ingram
sumber
119
.NET 4.6 yang akan datang (akan dirilis akhir tahun ini) memperkenalkan dukungan untuk ini. Lihat DateTimeOffset.FromUnixTimeSecondsdan DateTimeOffset.ToUnixTimeSecondsmetode. Ada metode untuk unix-waktu milidetik juga.
Jeppe Stig Nielsen

Jawaban:

1018

Inilah yang Anda butuhkan:

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

Atau, untuk Java (yang berbeda karena cap waktu dalam milidetik, bukan detik):

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;
}
ScottCher
sumber
5
Waktu di Windows ditangani oleh HAL dan hanya mendekati akurat dalam 1 ms hingga 15 ms. Info lebih lanjut tersedia di Windows Internal sekitar halaman 112, jika ada yang tertarik.
Jim Schubert
16
Jawaban ini berisiko memotong detik ... Double adalah angka mengambang. Argumennya harus int / long / etc.
ccook
44
Metode-metode ini harus menerima panjang atau int, bukan ganda. Juga, untuk perangko waktu Java, tidak perlu membagi 1000 dan bulat. Lakukan sajadtDateTime.AddMilliseconds(javaTimeStamp).ToLocalTime();
Justin Johnson
11
Apakah Anda baru saja melewatkan "sebaliknya"? Bagaimana kami mengonversi DateTime ke stempel waktu?
Jonny
38
Untuk .NET Framework 4.6 dan di atasnya ada sekarang static DateTimeOffset.FromUnixMillisecondsdan DateTimeOffset.ToUnixMilliseconds.
rookie1024
422

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

  • Batalkan waktu dalam detik ke UTC DateTimeOffset:

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

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

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

long unixTimeStampInMilliseconds = dateTimeOffset.ToUnixTimeMilliseconds();

Catatan: Metode ini dikonversi ke dan dari UTC DateTimeOffset. Untuk mendapatkan DateTimerepresentasi cukup gunakan DateTimeOffset.UtcDateTimeatau DateTimeOffset.LocalDateTimeproperti:

DateTime dateTime = dateTimeOffset.UtcDateTime;
i3arnon
sumber
Ini tidak mengubah waktu ke waktu lokal. Anda mendapatkan UTC jika Anda menggunakan DateTimeOffset.FromUnixTimeSeconds ().
Berend de Boer
4
@BerenddeBoer Anda dapat menggunakan ToLocalTimejika Anda mau.
i3arnon
1
Untuk mendapatkan waktu saat ini, Anda dapat menggunakanlong unixMilliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Dan Diplo
219

Stempel DateTime ke UNIX:

public static double DateTimeToUnixTimestamp(DateTime dateTime)
{
    return (TimeZoneInfo.ConvertTimeToUtc(dateTime) - 
           new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc)).TotalSeconds;
}
Dmitry Fedorkov
sumber
47

Dari Wikipedia :

UTC tidak berubah dengan perubahan musim, tetapi waktu setempat atau waktu sipil dapat berubah jika yurisdiksi zona waktu mengamati waktu musim panas (waktu musim panas). Sebagai contoh, waktu lokal di pantai timur Amerika Serikat adalah lima jam di belakang UTC selama musim dingin, tetapi empat jam di belakang sementara penghematan siang hari diamati di sana.

Jadi ini kode saya:

TimeSpan span = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0,DateTimeKind.Utc));
double unixTime = span.TotalSeconds;
gl051
sumber
2
tapi ini mengembalikan dua kali lipat, saya kira orang perlu lama?
knocte
30

Hati-hati, jika Anda membutuhkan ketelitian yang lebih tinggi dari milidetik!

Metode .NET (v4.6) (mis. FromUnixTimeMilliseconds ) tidak memberikan ketepatan ini.

AddSeconds dan AddMilliseconds juga memotong mikrodetik di ganda.

Versi ini memiliki presisi tinggi:

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;
}
Felix Keil
sumber
2
Ini jawaban yang benar. Yang lain mendapatkan zona waktu salah pada konversi kembali dari timestamp.
IAMIC
untuk DateTime-> Java, hanya [kode] kembali (panjang) unixTimeStampInTicks / TimeSpan.TicksPerMilliSecond; [/ code]
Maks
Jadi di Anda UnixTimestampToDateTime, yang disediakan unixTimemasih dalam hitungan detik, bukan?
Ngoc Pham
@NgocPham ya itu
Felix Keil
14

Lihat 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);
    }
}
orad
sumber
Ini bagus, tapi saya sarankan perubahan kecil: Penggunaan tipe "panjang" harus diubah menjadi "Int32" atau "int". "Panjang" menunjukkan ada presisi yang signifikan, tetapi tidak ada. Semua matematika hanya tepat untuk 1 detik sehingga Int32 akan lebih sugestif dari apa yang Anda harapkan dari cap waktu Unix
JamesHoux
3
Saya pikir itu karena DateTime.TicksInt64 (panjang), jadi mereka menghindari pemeran tambahan.
orad
10

Untuk melengkapi jawaban ScottCher, saya baru-baru ini menemukan diri saya dalam skenario yang menyebalkan memiliki kedua cap waktu UNIX detik dan milidetik dicampur secara sewenang-wenang dalam satu set data input. Kode berikut tampaknya menangani ini dengan baik:

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);
}
Chris Thoman
sumber
1
Berhati-hatilah saat tidak menggunakan argumen DateTimeKind, karena DateTime yang dibuat akan berada di waktu lokal komputer (terima kasih untuk kodenya, Chris)!
Sam Grondahl
1
Hati-hati - ini tidak akan berfungsi untuk cap waktu unix untuk tanggal sebelum tanggal 11 Januari 1978 jika mereka terwakili dalam milidetik. Stempel data unix 253324800 (detik) memberikan tanggal yang benar dari 11.01.1978, sedangkan representasi milidetik 253324800000 memberikan tanggal 18.07.9997. Ini mungkin berhasil untuk kumpulan data Anda, tetapi itu bukan solusi umum.
Øyvind
8

Konversi waktu unix adalah baru di .NET Framework 4.6.

Anda sekarang dapat dengan lebih mudah mengonversi nilai tanggal dan waktu ke atau dari jenis .NET Framework dan waktu Unix. Ini bisa diperlukan, misalnya, ketika mengonversi nilai waktu antara klien JavaScript dan server .NET. API berikut telah ditambahkan ke struktur DateTimeOffset :

static DateTimeOffset FromUnixTimeSeconds(long seconds)
static DateTimeOffset FromUnixTimeMilliseconds(long milliseconds)
long DateTimeOffset.ToUnixTimeSeconds()
long DateTimeOffset.ToUnixTimeMilliseconds()
Fred
sumber
Ini tidak memberi Anda waktu lokal, Anda mendapatkan UTC.
Berend de Boer
@BerenddeBoer Itu default yang masuk akal. Anda dapat menerapkan offset khusus setelah itu seperti yang Anda inginkan.
Deilan
1
@BerenddeBoer Itu salah paham apa waktu unix itu. Waktu Unix adalah detik sejak tengah malam, 1 Januari 1970, UTC. Tidak masalah di mana Anda berada, jumlah detik sejak zaman itu tidak berubah. Mengubahnya menjadi tampilan waktu lokal yang dapat dibaca manusia terpisah dari representasi universal ini, sebagaimana mestinya.
Tanktalus
5

Saya menemukan jawaban yang tepat hanya dengan membandingkan konversi ke 1/1/1970 tanpa penyesuaian waktu setempat;

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;
n8CodeGuru
sumber
4
var dt = DateTime.Now; 
var unixTime = ((DateTimeOffset)dt).ToUnixTimeSeconds();

// 1510396991

var dt = DateTimeOffset.FromUnixTimeSeconds(1510396991);

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

mesut
sumber
4

Dari .net 4.6, Anda dapat melakukan ini:

var dateTime = DateTimeOffset.FromUnixTimeSeconds(unixDateTime).DateTime;
Yang Zhang
sumber
3
DateTime unixEpoch = DateTime.ParseExact("1970-01-01", "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture);
DateTime convertedTime = unixEpoch.AddMilliseconds(unixTimeInMillisconds);

Tentu saja, seseorang dapat membuat unixEpochstatis global, jadi itu hanya perlu muncul sekali dalam proyek Anda, dan satu dapat digunakan AddSecondsjika waktu UNIX dalam detik.

Untuk pergi ke arah lain:

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

Potong ke Int64 dan / atau gunakan TotalSecondssesuai kebutuhan.

Hot Licks
sumber
3

Ditulis ekstensi paling sederhana yang berfungsi untuk kita. Jika ada yang mencarinya ...

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

        return DateTimeOffset.FromUnixTimeSeconds(long.Parse(unixTimeStamp)).UtcDateTime;
    }
}
Riyaz Hameed
sumber
3
System.DateTimeOffset.Now.ToUnixTimeSeconds()
AMieres
sumber
2

Kutu Unix adalah 1 detik (jika saya ingat dengan baik), dan kutu .NET adalah 100 nanodetik.

Jika Anda pernah mengalami masalah dengan nanodetik, Anda mungkin ingin mencoba menggunakan AddTick (nilai 10000000 *).

Luk
sumber
3
Unix adalah masa lalu detik - yaitu 1/1/70.
ScottCher
1

Yang saya butuhkan untuk mengkonversi struct timeval (detik, mikrodetik) mengandung UNIX timeke DateTimetanpa kehilangan presisi dan belum menemukan jawaban di sini jadi saya pikir saya hanya bisa menambahkan saya:

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
1

Anda dapat menggunakan DateTimeOffset .

Sebagai contoh. Saya memiliki objek DateTime

var dateTime=new DateTime();

Jika saya ingin mengonversikannya ke waktu prangko Unix, saya dapat mencapai sebagai berikut

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

Untuk informasi lebih lanjut silakan kunjungi tautan ini: DateTimeOffset.ToUnixTimeSeconds Method

Ramil Aliyev
sumber
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();
        }
    }

Anda dapat menghubungi UnixTime.UnixTimeToDateTime (double datetime))

madan
sumber
-2

Untuk .NET 4.6 dan yang lebih baru:

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);
    }
}
superlogikal
sumber
4
Saya tidak mengerti. Di .NET 4.6, BCL sudah memiliki metode-metode tersebut (lihat misalnya komentar saya untuk pertanyaan di atas, atau beberapa jawaban baru lainnya (2015). Jadi, apa gunanya menulisnya lagi? Apakah maksud Anda bahwa jawaban Anda adalah solusi untuk versi sebelum 4.6?
Jeppe Stig Nielsen