在資料庫儲存、跨平台序列化、高精度時間運算等場景,將 DateTime 轉換為長整數(Ticks)是常見需求。本文完整說明 Ticks 定義、雙向轉換、OADate 相容格式、時區處理與最佳實踐。
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)
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、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}");
// 建構時指定 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 混淆
DateTimeOffset now = DateTimeOffset.UtcNow;
long ticks = now.Ticks; // 相對 0001/1/1 UTC 的 ticks
TimeSpan offset = now.Offset; // 時區偏移
// 儲存建議:Ticks + Offset 兩欄位,或單純 UTC Ticks
掌握 Ticks 轉換細節,能在高精度計時、跨系統整合、資料庫設計中避開時區陷阱,建立可靠的時間處理基礎設施。