首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# DateTime 與長整數 Ticks 雙向轉換完整指南

     編輯:關於C#

在資料庫儲存、跨平台序列化、高精度時間運算等場景,將 DateTime 轉換為長整數(Ticks)是常見需求。本文完整說明 Ticks 定義、雙向轉換、OADate 相容格式、時區處理與最佳實踐。

Ticks 核心定義

  • 基準時間:0001 年 1 月 1 日 00:00:00.000 (UTC)
  • 單位:1 Tick = 100 奈秒 = 0.1 微秒 = 10-7 秒
  • 範圍:DateTime.MinValue.Ticks (0) 至 DateTime.MaxValue.Ticks (3,155,378,975,999,999,999)
  • 屬性:DateTime.Ticks 為 long 唯讀屬性

基本雙向轉換

using System;

// DateTime → Ticks
DateTime now = DateTime.Now;
long ticks = now.Ticks;
Console.WriteLine($"Ticks: {ticks}"); // 例:638123456789012345

// Ticks → DateTime
DateTime restored = new DateTime(ticks);
Console.WriteLine($"Restored: {restored}"); // 還原原始時間

// 靜態建構方法
DateTime fromTicks = DateTime.FromTicks(ticks); // 等同 new DateTime(ticks)

資料庫儲存建議

| 資料庫類型 | 對應型別 | 優點 | 缺點 | |------------|----------|------|------| | SQL Server | BIGINT | 效能最佳、索引友善、無時區歧義 | 需應用層轉換 | | PostgreSQL | BIGINT | 同上 | 同上 | | MySQL | BIGINT | 同上 | 同上 | | Oracle | NUMBER(20) | 精度足夠 | 無原生 BIGINT | | SQLite | INTEGER | 8 位元組有號整數 | 需應用層轉換 |
// Entity Framework Core 實體定義
public class EventLog
{
    public long Id { get; set; }
    
    // 儲存為 Ticks (BIGINT)
    public long OccurredAtTicks { get; set; }
    
    // 非對應屬性:方便業務邏輯使用
    public DateTime OccurredAt
    {
        get => new DateTime(OccurredAtTicks, DateTimeKind.Utc);
        set => OccurredAtTicks = value.Ticks;
    }
}

VB6 / COM 相容:OADate 格式

VB6、Excel、COM 使用 OLE Automation Date (OADate):以 1899/12/30 為基準的雙精度浮點數,整數部分為天數,小數部分為一天的比例。

// DateTime → OADate (double)
double oaDate = DateTime.Now.ToOADate();
Console.WriteLine($"OADate: {oaDate}"); // 例:45123.654321

// OADate → DateTime
DateTime fromOa = DateTime.FromOADate(oaDate);
Console.WriteLine($"Restored: {fromOa}");

適用場景

  • Excel 自動化(儲存格日期值)
  • VB6 遷移專案互通
  • COM 介面日期參數傳遞
  • OLE DB / ADO 資料存取

時區與 Kind 關鍵處理

// 建構時指定 Kind
var utc = new DateTime(ticks, DateTimeKind.Utc);
var local = new DateTime(ticks, DateTimeKind.Local);
var unspecified = new DateTime(ticks, DateTimeKind.Unspecified);

// 轉換
DateTime utcTime = DateTime.SpecifyKind(localTime, DateTimeKind.Utc); // 不改變值,只改標記
DateTime converted = TimeZoneInfo.ConvertTime(localTime, TimeZoneInfo.Utc); // 實際轉換

// 最佳實踐:統一儲存 UTC Ticks
public static long ToUtcTicks(DateTime dt)
{
    return dt.Kind switch
    {
        DateTimeKind.Utc => dt.Ticks,
        DateTimeKind.Local => dt.ToUniversalTime().Ticks,
        _ => throw new ArgumentException("Unspecified Kind 不允許,請明確指定")
    };
}

高精度運算優勢

// Ticks 運算避免浮點誤差
long start = DateTime.UtcNow.Ticks;
// ... 執行作業 ...
long end = DateTime.UtcNow.Ticks;
long elapsedTicks = end - start;
TimeSpan elapsed = TimeSpan.FromTicks(elapsedTicks);

Console.WriteLine($"耗時:{elapsed.TotalMilliseconds:F3} ms");

常見陷阱與解決方案

| 陷阱 | 說明 | 解決方案 | |------|------|----------| | 忽略 Kind 導致時區錯誤 | 儲存 Local 時間的 Ticks,還原時視為 UTC | 統一轉 UTC 儲存,或儲存 Kind 額外欄位 | | Ticks 溢位 | 極大日期超出 long 範圍 | 正常業務不會觸及,Year 9999 仍安全 | | 序列化格式不一致 | JSON 預設 ISO 8601 字串,非 Ticks | 明確指定序列化格式或自訂 Converter | | 資料庫時區設定干擾 | SQL Server `datetime` 無時區資訊 | 儲存 UTC Ticks 於 BIGINT,應用層處理轉換 |

現代替代:DateTimeOffset

// 內建時區偏移,避免 Kind 混淆
DateTimeOffset now = DateTimeOffset.UtcNow;
long ticks = now.Ticks; // 相對 0001/1/1 UTC 的 ticks
TimeSpan offset = now.Offset; // 時區偏移

// 儲存建議:Ticks + Offset 兩欄位,或單純 UTC Ticks

掌握 Ticks 轉換細節,能在高精度計時、跨系統整合、資料庫設計中避開時區陷阱,建立可靠的時間處理基礎設施。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved