Nasıl C # çağında dönüştürebilirsiniz?


377

Unix dönemini C # ile gerçek zamana nasıl dönüştürürsünüz ? (Dönem 1/1/1970)


1
Bir şeyi kaçırmadıkça, "çağ" sadece belirli bir zaman işleyişi planının başlangıç ​​noktasıdır. Örnekler arasında 1/1/0001, 1/1/1970 ve 1/1/2000 bulunur. Bu daha çok, bir planın kendisinden ziyade bir planın niteliğidir.
Bob Kaufman

8
Dönemden bu yana geçen süre, 1 Ocak 1970 UTC'den bu yana geçen saniye sayısıdır.
Taylor Leese

13
@Taylor Bu unix zamanı için bir dönem ve muhtemelen doğru, ama geçerli tek dönem değil. Unix time kullanıcıları bu noktada kendilerini karıştırmamalıdır.
Joel Coehoorn

Dup, diğer cevapları ile: stackoverflow.com/q/3354893/712526
jpaugh

Yanıtlar:


563

1 Ocak 1970'te gece yarısından bu yana (UTC) geçen saniye sayısı olarak tanımlanan Unix zamanını kastettiğini varsayıyorum .

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
Bu düzgün çalışması için .AddSeconds .AddMilliseconds değiştirmek zorunda kaldı. Doğru sonucu almak için numaranızın Saniye veya Milisaniye cinsinden geldiğini bilmeniz gerekir. Örneğin, şu tarih: 1406310305188 (25 Temmuz 2014). epochconverter.com ayrıca dönüşüm sonuçlarınızı kontrol etmenizi sağlar.
jrandomuser

5
Parametre türünü ikiye değiştirmelisiniz (çünkü AddSeconds ikiyi kabul eder ve bu nedenle ikiye indirilir) veya yöntem açıklamasına argümandaki 64 bitlik kesimin yalnızca 53'ünün korunacağını bildirir.
tomosius

6
@jrandomuser: Unix dönemi geleneksel olarak The Epoch'tan bu yana saniye olarak gösterilir . O zamandan beri The Epoch'tan (örneğin JavaScript) milisaniye kullanmak yaygınlaşıyor , ancak klasik tanım saniyeler. Alt satırda, sadece giriş değerinizin ne olduğunu (saniye, milisaniye, keneler, her neyse) bilin ve doğru AddXYZyöntemi kullanın .
TJ Crowder

İlk olarak AddMilliseconds ile deneyin ve yıl hala 1970 ise AddSeconds yapın. Bu şekilde milisaniye veya saniye hakkında endişelenmenize gerek kalmadan her zaman çalışır. Ayrıca taşma engellenmesini önleyebilirsiniz. AddSeconds'a büyük bir sayı iletilmesi kodun çökmesine neden olur
Tono Nam

213

Net (v4.6) en son sürümü sadece dahili eklendi Unix zaman dönüşümleri için destek. Bu, saniye veya milisaniye ile gösterilen Unix zamanına ve Unix zamanını içerir.

  • Unix süresini saniye olarak DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset saniye cinsinden Unix zamanı:

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • Milisaniye cinsinden Unix süresi DateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset milisaniye cinsinden Unix zamanı:

long unixTimeStampInMilliseconds= dateTimeOffset.ToUnixTimeMilliseconds();

Not: Bu yöntemler ve cihazlara dönüştürülür DateTimeOffset. DateTimeTemsil almak için DateTimeOffset.DateTimeözelliği kullanmanız yeterlidir :

DateTime dateTime = dateTimeOffset.UtcDateTime;

1
Bu sorunu 'DateTimeOffset' does not contain a definition for 'FromUnixTimeSeconds'nasıl çözebilirim?
Happy Bird

@HappyBird .NET 4.6 veya daha üst sürümünde misiniz?
i3arnon

Aynı şey - 4.7.2 ve DateTimeOffset için hiçbir FromUnixTimeMilliseconds yöntemi yok ...
Mikhail_Sam

Anladım. Yeni nesne yaratmam gerekmiyor. Statik bir yöntem.
Mikhail_Sam

Varsayılan değerleri ilk bakışta biraz kafa karıştırıcı buldum. BC 1000 milisaniyeden saniyeye dönüştürme faktörüdür.
BluE

169

LukeH'ye verilen tüm krediyle, kolay kullanım için bazı uzantı yöntemlerini bir araya getirdim:

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

Aşağıdaki CodesInChaos yukarıdaki açıklama bir FromUnixTimedöndürür notDateTime bir ile Kindait Utciyidir, ama hangi yukarıdaki ToUnixTimeçok daha şüpheli ki dikkate almaz tür ne içindir DateTimeverilen dateolduğunu. İzin vermek için datebireyin Kindvarlık ya Utcya Local, kullanım 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);
}

ToUniversalTimebir Local(veya Unspecified) dönüştürürDateTime için Utc.

DateTime'dan epoch'a geçerken epoch DateTime örneğini oluşturmak istemiyorsanız şunları da yapabilirsiniz:

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

6
ToUnixTimeyalnızca tarih Utc'deyse doğru çalışır. Bir çek ekleyin veya dönüştürün. (Şahsen ben çek tercih ederim)
CodesInChaos

2
Sadece bunun neden işe yaramadığını anlayarak geçen saati geçirdim. Saniyeler içinde çalışmanız milliseconds gerekmiyor !!!
KristianB

7
@KristianB: "Unix zamanı" geleneksel olarak saniye, milisaniye değil, Epoch'tan beri, bu günlerde birisinin hangi tanımı kullandığını kontrol etmeye dikkat ettim. Saniyeler yeterince iyiydi ve bize Epoch'un her iki tarafına da işaretli 32 bit değerlerde makul bir aralık verdi. (Ve bu yüzden 19 Ocak 2038'de saat 03:14'ten sonra GMT bazıları için kötü bir zaman olabilir ...) Milisaniye kullanmak, rutin olarak 64 bitlik değerler (her iki integral) atmak sayesinde daha modern bir uygulamadır. ve çift kesinlikli IEEE-754) ...
TJ Crowder

5
Kod için teşekkürler. Epoch tabanını oluştururken sadece küçük bir öneri: Milisaniye değerini açıkça 0 olarak ayarladığınızdan emin olun. Yani var epoch = new DateTime (1970, 1, 1, 0 / * h * /, 0 / * m * /, 0 / * s * /, 0 / * ms * /, DateTimeKind.Utc); Açıkça ayarlamazsanız, milisaniye değeri 1 olarak ortaya çıkar. Bu, testlerimde bazı tutarsızlıklara neden oldu.
ctrlplusb

1
Kullanmalısınız AddMillisecondsve Double NOT Float kullanmalısınız. Aksi takdirde yanlış bir zamanla karşılaşırsınız.
Axel

25

Aslında saniye değil, Milisaniye (milisaniye) eklemek istiyorsunuz. Saniye eklemek size aralık dışı bir istisna verecektir.


Neden? epochconverter.com 1/1/970 ms'den bu yana geçen saniye sayısını eklediğinizi söylüyor.
Jamie R Rytlewski

Eğer ms'den gidiyorsanız bariz istersiniz AddMillisve saniyeler içinde başlıyorsanız bariz istersiniz AddSeconds.
Ayakkabı

Saniyeler kullanırken menzil dışına çıkmaya devam ettiğim aynı sorunu yaşadım. Dönüştürmeye çalıştığım unix zamanı milisaniye cinsindeydi. Saniyeler içinde olduğunu düşündüm. Sanırım bazı unix zamanları milisaniye cinsinden ölçülür.
DoodleKana

Unix Süresi genellikle saniye olarak ifade edilir, ancak 0.001 geçerli bir saniye sayısıdır (= 1 ms). Şüphe duyduğunuzda, mümkün olan maksimum hassasiyeti kullanın.
Scott

9

Daha iyi performans istiyorsanız bu sürümü kullanabilirsiniz.

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

Net471 altında hızlı bir karşılaştırmadan (BenchmarkDotNet) bu numarayı alıyorum:

        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 |

LukeH versiyonuna göre 2 kat daha hızlı (performans mater ise)

Bu, DateTime'ın dahili olarak çalışma şekline benzer.


9

DateTimeOffset.ToUnixTimeMilliseconds () yöntemini kullanın . 1970-01-01T00: 00: 00.000Z'den bu yana geçen milisaniye sayısını döndürür.

Bu yalnızca Framework 4.6 veya üstü ile desteklenir

var EPOCH = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

Burada iyi belgelenmiştir DateTimeOffset.ToUnixTimeMilliseconds

Diğer çıkış yolu aşağıdakileri kullanmaktır

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

EPOCH'u sadece saniyeler içinde almak için

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

ve Epochdeğerini DateTimeaşağıdaki yöntemle dönüştürün

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

DateTime.Ticks - her kene "yüz nanosaniye" dir, hatırlanması ekstra bir 'şey' yapar. Her ikisini de .Ticksatlarsanız, DateTime çıkarma işleminden güzel bir TimeSpan örneği geri alınır.
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);
}

DateTime nesnesi için ToUniversalTime () kullanmalıdır.


5

Dönem dönüşümü için aşağıdaki uzantı yöntemlerini kullanıyorum

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

Milisaniye veya saniye kullanma konusunda endişelenmemek için yapmanız gerekenler:

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

Dönem zamanı saniye cinsindeyse, 1972 yılını milisaniye ekleyerek geçemezsiniz.


1

4.6 kullanmıyorsanız, bu yardımcı olabilir Kaynak: 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;
    }    

Örneğin JWT'den teşekkürler. Bu arada, kullanmak için, sadece şunu kullanın: using Microsoft.IdentityModel.Tokens; ... EpochTime.GetIntDate(dateTime);
likit

0

Eğer bir dönüştürmek için gereken timeval yapı içeren (saniye, mikrosaniye) UNIX timeiçin DateTimekesinlik kaybetmeden bu nasıl:

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

İşte benim çözümüm:

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
bu artık yıllar ve artık saniye vb.
Jodrell

1
Önceki yorumu genişletmek için, zamanın neden karmaşık olduğunu ve bunu neden kendiniz denememeniz gerektiğini açıklayan kısa bir video var: youtube.com/watch?v=-5wpm-gesOY
vmrob
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.