คุณจะแปลงเวลายุคใน C # ได้อย่างไร


377

คุณจะแปลงเวลายุค Unix เป็นเวลาจริงใน C # ได้อย่างไร (เริ่มตั้งแต่ 1/1/1970)


1
หากไม่มีสิ่งใดหายไป "ยุค" เป็นเพียงจุดเริ่มต้นของรูปแบบการบอกเวลาเฉพาะ ตัวอย่าง ได้แก่ 1/1/0001, 1/1/1970 และ 1/1/2000 มันเป็นคุณสมบัติของแบบแผนมากกว่าแบบแผน (เช่นจูเลียน) นั่นเอง
Bob Kaufman

8
เวลาตั้งแต่ยุคคือจำนวนวินาทีตั้งแต่ 1 มกราคม 1970 UTC
Taylor Leese

13
@Taylor นั่นเป็นยุคสำหรับเวลา unix และมันอาจจะถูก แต่ไม่ใช่ยุคที่ถูกต้องเท่านั้น ผู้ใช้เวลา Unix ไม่ควรสับสนในจุดนั้น
Joel Coehoorn

ทำซ้ำกับคำตอบอื่น ๆ : stackoverflow.com/q/3354893/712526
jpaugh

คำตอบ:


563

ฉันคิดว่าคุณหมายถึงเวลา Unixซึ่งถูกกำหนดให้เป็นจำนวนวินาทีตั้งแต่เที่ยงคืน (UTC) ในวันที่ 1 มกราคม 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
เพื่อให้สิ่งนี้ทำงานได้อย่างถูกต้องฉันต้องเปลี่ยน. เพิ่มวินาทีเป็น. AddMilliseconds คุณจะต้องทราบว่าหมายเลขของคุณมาจากวินาทีหรือมิลลิวินาทีเพื่อให้ได้ผลลัพธ์ที่ถูกต้อง ดังนั้นเช่นวันที่ดังต่อไปนี้: 1406310305188 (25 กรกฎาคม 2014) epochconverter.comจะช่วยให้คุณตรวจสอบผลลัพธ์การแปลงของคุณ
jrandomuser

5
คุณควรเปลี่ยนประเภทพารามิเตอร์เป็นสองเท่า (เนื่องจาก AddSeconds ยอมรับ double และดังนั้นจะลดลงเป็นสองเท่า) หรือเพิ่มข้อจำกัดความรับผิดชอบไปที่คำอธิบายวิธีการซึ่งมีความแม่นยำเพียง 53 จาก 64 บิตในอาร์กิวเมนต์จะถูกเก็บไว้
tomosius

6
@jrandomuser: เวลายุค Unix ถูกแสดงแบบดั้งเดิมเป็นวินาทีตั้งแต่ยุค เป็นเรื่องปกติที่จะใช้มิลลิวินาทีนับตั้งแต่ The Epoch (ตัวอย่างเช่น JavaScript) แต่นิยามคลาสสิกคือวินาที ด้านล่างบรรทัดเพิ่งรู้ว่าค่าอินพุตของคุณคืออะไร (วินาที, มิลลิวินาที, ติ๊ก, อะไรก็ตาม) และใช้AddXYZวิธีการที่เหมาะสม
TJ Crowder

ลองครั้งแรกกับ AddMilliseconds และถ้าปียังคงเป็น 1970 ให้ทำ AddSeconds วิธีนี้จะทำงานตลอดเวลาโดยไม่ต้องกังวลกับมิลลิวินาทีหรือวินาที นอกจากนี้คุณสามารถป้องกันการไหลล้น การส่งผ่านจำนวนมากไปยัง AddSeconds จะทำให้รหัสขัดข้อง
Tono Nam

213

รุ่นล่าสุดของสุทธิ (v4.6)เพียงแค่เพิ่มการสนับสนุนในตัวสำหรับการแปลงเวลายูนิกซ์ ซึ่งรวมถึงเวลาทั้งจากและเวลา Unix ที่แสดงด้วยวินาทีหรือมิลลิวินาที

  • เวลา Unix ในไม่กี่วินาทีเพื่อDateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset ถึงเวลา Unix ในไม่กี่วินาที:

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • เวลา Unix ในหน่วยมิลลิวินาทีถึงDateTimeOffset:

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset ถึงเวลา Unix เป็นมิลลิวินาที:

long unixTimeStampInMilliseconds= dateTimeOffset.ToUnixTimeMilliseconds();

หมายเหตุ: DateTimeOffsetวิธีการเหล่านี้แปลงไปและกลับจาก ในการรับการเป็นDateTimeตัวแทนเพียงใช้DateTimeOffset.DateTimeคุณสมบัติ:

DateTime dateTime = dateTimeOffset.UtcDateTime;

1
ฉันได้รับ'DateTimeOffset' does not contain a definition for 'FromUnixTimeSeconds'ฉันจะแก้ไขปัญหานี้อย่างไร
Happy Bird

@HappyBird คุณอยู่บน. NET 4.6 หรือสูงกว่า?
i3arnon

สิ่งเดียวกัน - 4.7.2 และไม่มีวิธี FromUnixTimeMilliseconds สำหรับ DateTimeOffset ...
Mikhail_Sam

ฉันเข้าใจแล้ว. ฉันไม่จำเป็นต้องสร้างวัตถุใหม่ มันเป็นวิธีคงที่
Mikhail_Sam

ฉันพบว่าค่าเริ่มต้นค่อนข้างสับสนเมื่อมองแวบแรก Bc 1000 เป็นปัจจัยในการแปลงจากมิลลิวินาทีเป็นวินาที
BluE

169

ด้วยเครดิตทั้งหมดถึงลุคฉันได้รวบรวมวิธีการขยายไว้ใช้งานง่าย:

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

หมายเหตุความคิดเห็นด้านล่างจาก CodesInChaos ว่าข้างต้นFromUnixTimeส่งกลับDateTimeด้วยKindของUtcซึ่งเป็นดี แต่ข้างต้นToUnixTimeเป็นมากขึ้นในการที่ผู้ต้องสงสัยไม่บัญชีสำหรับสิ่งที่ชนิดของDateTimeที่ได้รับdateคือ เพื่อให้date's Kindเป็นอย่างใดอย่างหนึ่งUtcหรือLocalใช้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);
}

ToUniversalTimeจะแปลงLocal(หรือUnspecified) DateTimeเป็นUtcเพื่อ

หากคุณไม่ต้องการสร้างอินสแตนซ์ยุคสมัยเมื่อย้ายจาก DateTime ไปยังยุคคุณยังสามารถทำได้:

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

6
ToUnixTimeทำงานได้อย่างถูกต้องหากวันที่อยู่ใน Utc เพิ่มการตรวจสอบหรือแปลง (โดยส่วนตัวแล้วฉันชอบเช็ค)
CodesInChaos

2
เพิ่งใช้เวลาชั่วโมงที่ผ่านมาหาสาเหตุว่าทำไมมันถึงใช้งานไม่ได้ คุณต้องทำงานในmilliseconds ไม่กี่วินาที !!!
KristianB

7
@ KristianB: "Unix time" เป็นวินาทีดั้งเดิมไม่ใช่มิลลิวินาทีเนื่องจาก The Epoch แม้ว่าวันนี้ฉันระวังที่จะตรวจสอบว่ามีใครใช้คำจำกัดความ ไม่กี่วินาทีที่เคยดีพอและทำให้เรามีช่วงที่เหมาะสมทั้งสองข้างของ The Epoch ในค่า 32- เซ็นชื่อ (และเป็นเหตุผลว่าทำไมหลังจาก 3:14 น. ในวันที่ 19 มกราคม 2038 GMT อาจเป็นช่วงเวลาที่ไม่ดีสำหรับบางคน ... ) การใช้มิลลิวินาทีเป็นวิธีปฏิบัติที่ทันสมัยมากขึ้นเนื่องจากเราสามารถโยนค่า 64- บิตเป็นประจำ และความแม่นยำสองเท่า IEEE-754) ...
TJ Crowder

5
ขอบคุณสำหรับรหัส เพียงคำแนะนำเล็กน้อยเมื่อสร้างฐาน Epoch: ให้แน่ใจว่าตั้งค่ามิลลิวินาทีอย่างชัดเจนเป็น 0 เช่น var epoch = new DateTime (1970, 1, 1, 0 / * h * /, 0 / * m * /, 0 / * s * /, 0 / * ms * /, DateTimeKind.Utc); หากคุณไม่ได้ตั้งค่าไว้อย่างชัดเจนค่ามิลลิวินาทีน่าจะออกมาเป็น 1 ซึ่งทำให้เกิดความไม่สอดคล้องกันในการทดสอบของฉัน
ctrlplusb

1
คุณควรใช้AddMillisecondsและคุณควรใช้ Double NOT Float มิฉะนั้นคุณจะจบลงด้วยเวลาที่ผิด
Axel

25

คุณต้องการ AddMilliseconds (มิลลิวินาที) ไม่ใช่วินาที การเพิ่มวินาทีจะทำให้คุณมีข้อยกเว้นนอกช่วง


ทำไมถึงเป็นอย่างนั้น? epochconverter.comมันบอกว่าคุณเพิ่มจำนวนวินาทีตั้งแต่ 1/1/970 ไม่ใช่ ms
Jamie R Rytlewski

หากคุณกำลังจะจาก MS คุณต้องการที่เห็นได้ชัดและถ้าคุณกำลังเริ่มต้นจากวินาทีที่คุณต้องการอย่างเห็นได้ชัดAddMillis AddSeconds
รองเท้า

ฉันมีปัญหาเดียวกันกับที่ฉันยังอยู่นอกขอบเขตเมื่อใช้วินาที เวลายูนิกซ์ที่ฉันพยายามแปลงอยู่ในหน่วยมิลลิวินาที ฉันคิดว่ามันเป็นวินาที ฉันคิดว่าบางเวลายูนิกซ์วัดเป็นหน่วยเป็นมิลลิวินาที
DoodleKana

โดยทั่วไปเวลา Unix จะแสดงเป็นวินาที แต่ 0.001 เป็นจำนวนวินาทีที่ถูกต้อง (= 1 ms) เมื่อสงสัยให้ใช้ความแม่นยำสูงสุดเท่าที่จะทำได้
สกอตต์

9

หากคุณต้องการประสิทธิภาพที่ดีขึ้นคุณสามารถใช้เวอร์ชันนี้ได้

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

จากการวัดประสิทธิภาพอย่างรวดเร็ว (BenchmarkDotNet) ภายใต้ net471 ฉันได้รับหมายเลขนี้:

        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 |

เร็วขึ้น 2 เท่าเมื่อเทียบกับเวอร์ชั่นของ LukeH (หากมีประสิทธิภาพ)

ซึ่งคล้ายกับการทำงานของ DateTime ภายใน


9

ใช้วิธีDateTimeOffset.ToUnixTimeMilliseconds () มันคืนค่าจำนวนมิลลิวินาทีที่ผ่านไปตั้งแต่ 1970-01-01T00: 00: 00.000Z

รองรับเฉพาะกับ Framework 4.6 หรือสูงกว่าเท่านั้น

var EPOCH = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

มันบันทึกไว้ที่นี่ดี DateTimeOffset.ToUnixTimeMilliseconds

อีกวิธีคือการใช้ต่อไปนี้

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

ในการรับ EPOCH ภายในไม่กี่วินาทีคุณสามารถใช้งานได้

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

และแปลงEpochไปDateTimeด้วยวิธีการดังต่อไปนี้

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

DateTime.Ticks - ขีดแต่ละอันคือ "หนึ่งร้อยนาโนวินาที" ทำให้เป็นสิ่งพิเศษที่ต้องจดจำ หากไม่ได้ใส่ทั้งคู่.Ticksจะได้รับอินสแตนซ์ของ TimeSpan ที่ดีจากการลบวันที่และเวลา
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);
}

ควรใช้ ToUniversalTime () สำหรับวัตถุ DateTime


5

ฉันใช้วิธีการต่อไปนี้สำหรับการแปลงยุค

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

หากไม่ต้องกังวลกับการใช้มิลลิวินาทีหรือวินาทีให้ทำดังนี้

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

หากเวลายุคในหน่วยวินาทีนั้นไม่มีทางที่คุณสามารถผ่านปี 1972 เพิ่มมิลลิวินาที


1

หากคุณไม่ได้ใช้ 4.6 สิ่งนี้อาจช่วยที่มา: 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;
    }    

ขอบคุณสำหรับตัวอย่างจาก JWT โดยวิธีการใช้เพียงใช้: using Microsoft.IdentityModel.Tokens; ... EpochTime.GetIntDate(dateTime);
ของเหลว

0

ในกรณีที่คุณต้องการแปลงstruct timeval (วินาที microseconds) ที่มีUNIX timeไปDateTimeโดยไม่สูญเสียความแม่นยำนี้เป็นวิธีที่:

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

นี่คือทางออกของฉัน:

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
บัญชีนี้สำหรับ leap ปีและ leap วินาทีเป็นต้นหรือไม่
Jodrell

1
หากต้องการขยายความคิดเห็นก่อนหน้านี้ต่อไปนี้เป็นวิดีโอสั้น ๆ ที่อธิบายว่าทำไมเวลาจึงซับซ้อนและทำไมคุณไม่ควรลองทำเอง: youtube.com/watch?v=-5wpm-gesOY
vmrob
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.