博客 / 詳情

返回

C#.NET DateTime 最強入門到進階:格式化、轉換、UTC、時區全覆蓋

簡介

DateTimeSystem 命名空間中用於表示日期和時間的結構體,廣泛用於處理時間相關的操作,如存儲、計算、格式化等。

DateTime 結構概述

  • 定義:System.DateTime 是一個值類型(struct),表示自公元 0001 年 1 月 1 日午夜 00:00:00(DateTime.MinValue)起經過的“刻度”(ticks,1 tick = 100 納秒)數。
  • 內部存儲:一個 long 值(ticks)+ 一個 DateTimeKind 枚舉,指示時間的“種類”:

    • Unspecified:未指定是本地還是 UTC
    • Utc:協調世界時
    • Local:本地時區時間
  • 範圍:DateTime.MinValue(0001-01-01),DateTime.MaxValue(9999-12-31 23:59:59.9999999)
// 時間單位轉換
1 秒 = 10,000,000 Ticks
1 毫秒 = 10,000 Ticks
1 分鐘 = 600,000,000 Ticks

主要功能

表示日期和時間:

  • 包含年、月、日、時、分、秒、毫秒。
  • 支持 Kind 屬性(Utc、Local、Unspecified)。

時間操作:

  • 比較:Compare、CompareTo
  • 運算:加減時間(AddDays、AddHours 等)。
  • 時間差:Subtract 返回 TimeSpan

格式化:

  • 使用 ToString 格式化(如 "yyyy-MM-dd HH:mm:ss")。
  • 支持區域性(CultureInfo)。

轉換:

  • 與字符串、Unix 時間戳、數據庫時間互轉。

靜態屬性:

  • DateTime.Now:本地時間。
  • DateTime.UtcNowUTC 時間。
  • DateTime.Today:當前日期(時間為 00:00:00)。

核心屬性

屬性 説明
Now 返回本地時區當前時間
UtcNow 返回 UTC 當前時間
Today 返回本地時區當前日期(00:00:00 時分秒)
Date 取當前實例的日期部分,時間部分置 00:00:00
Year, Month, Day 年、月、日
Hour, Minute, Second, Millisecond 小時、分鐘、秒、毫秒
DayOfWeek 星期枚舉(DayOfWeek.Monday…)
DayOfYear 年內天數(1–366)
Kind 時間種類(Utc/Local/Unspecified
Ticks 自 0001-01-01 00:00:00 起的刻度數(100ns 為單位)
var dt = DateTime.Now;
Console.WriteLine($"{dt.Year}-{dt.Month}-{dt.Day} {dt.Hour}:{dt.Minute}:{dt.Second}, Kind={dt.Kind}");

構造與轉換

構造器

// 指定年月日時分秒
var dt1 = new DateTime(2025, 8, 8, 14, 30, 0);

// 指定 Kind
var dt2 = new DateTime(2025,8,8,14,30,0, DateTimeKind.Utc);

從 ticks

var dtTicks = new DateTime(637632000000000000L);

與 Unix 時間戳

// DateTime <-> Unix seconds
var unixEpoch = DateTimeOffset.FromUnixTimeSeconds(0).UtcDateTime;
long toUnix = ((DateTimeOffset)DateTime.UtcNow).ToUnixTimeSeconds();

與 DateTimeOffset

  • DateTimeOffset 推薦用於跨時區場景,包含一個偏移量字段,且不樸素依賴 Kind
  • DateTime 轉換:
var dto = new DateTimeOffset(dt);              // 按本地偏移
var dtoUtc = new DateTimeOffset(dt, TimeSpan.Zero);

特殊日期獲取

DateTime today = DateTime.Today; // 今天的午夜時間
DateTime min = DateTime.MinValue;
DateTime max = DateTime.MaxValue;
DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

DateTimeKind 與時區處理

DateTimeKind 枚舉

public enum DateTimeKind
{
    Unspecified = 0, // 未指定時區(默認)
    Utc = 1,         // UTC時間
    Local = 2        // 本地時間
}

時區轉換最佳實踐

// 創建帶時區信息的時間
DateTime utcTime = new DateTime(2023, 10, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime localTime = new DateTime(2023, 10, 1, 8, 0, 0, DateTimeKind.Local);

// 時區轉換
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");

// UTC轉本地時間
DateTime utcToChina = TimeZoneInfo.ConvertTimeFromUtc(utcTime, tz);

// 本地時間轉UTC
DateTime chinaToUtc = TimeZoneInfo.ConvertTimeToUtc(localTime, tz);

// 跨時區轉換
TimeZoneInfo nyTz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime chinaToNy = TimeZoneInfo.ConvertTime(localTime, tz, nyTz);

格式化與解析

標準格式化字符串

格式符 説明 示例輸出
"d" 短日期 2023-06-15
"D" 長日期 2023年6月15日
"t" 短時間 14:30
"T" 長時間 14:30:45
"f" 完整日期/時間 2023年6月15日 14:30
"F" 完整格式 2023年6月15日 14:30:45
"g" 常規短格式 2023-06-15 14:30
"G" 常規長格式 2023-06-15 14:30:45
"s" 可排序格式 2023-06-15T14:30:45
"u" 通用可排序 2023-06-15 14:30:45Z
"U" UTC完整格式 2023年6月15日 6:30:45

格式化

  • 標準格式
dt.ToString("o");  // ISO 8601 完整格式:2025-08-08T14:30:00.0000000Z
dt.ToString("s");  // 可排序格式:2025-08-08T14:30:00
dt.ToString("G");  // 默認長日期+長時間
dt.ToString("d");       // "2023/10/1"(短日期)
dt.ToString("D");       // "2023年10月1日"(長日期)
dt.ToString("t");       // "14:30"(短時間)
dt.ToString("T");       // "14:30:00"(長時間)
  • 自定義格式
dt.ToString("yyyy-MM-dd HH:mm:ss");      // 2025-08-08 14:30:00
dt.ToString("yyyy-MM-dd HH:mm:ss.fff");  // 帶毫秒
dt.ToString("dddd, MMM d yyyy");         // 星期幾, 月 日 年

解析

  • Parse / TryParse
DateTime.Parse("2025-08-08 14:30");
DateTime.TryParse("2025-08-08", out var dt);
  • 指定格式解析
DateTime.ParseExact("08/08/2025", "MM/dd/yyyy", CultureInfo.InvariantCulture);
DateTime.TryParseExact(input, new[] {"yyyy-MM-dd","MM/dd/yyyy"}, 
                       CultureInfo.InvariantCulture, DateTimeStyles.None, out dt);

日期時間組件訪問

屬性訪問

DateTime dt = new DateTime(2023, 10, 5, 14, 30, 45, 123);

int year = dt.Year;       // 2023
int month = dt.Month;     // 10
int day = dt.Day;         // 5
int hour = dt.Hour;       // 14
int minute = dt.Minute;   // 30
int second = dt.Second;   // 45
int millisecond = dt.Millisecond; // 123
long ticks = dt.Ticks;    // 638,000,000,000,000,000 + ...

DayOfWeek dayOfWeek = dt.DayOfWeek; // DayOfWeek.Thursday
int dayOfYear = dt.DayOfYear;       // 278 (10月5日是2023年第278天)

日期計算輔助

DateTime dt = new DateTime(2023, 2, 15);

// 獲取月份天數
int daysInFeb = DateTime.DaysInMonth(2023, 2); // 28

// 判斷閏年
bool isLeap2023 = DateTime.IsLeapYear(2023); // false
bool isLeap2024 = DateTime.IsLeapYear(2024); // true

// 獲取月份首日和末日
DateTime firstDayOfMonth = new DateTime(dt.Year, dt.Month, 1);
DateTime lastDayOfMonth = new DateTime(dt.Year, dt.Month, 
    DateTime.DaysInMonth(dt.Year, dt.Month));

日期時間運算與比較

算術運算

DateTime now = DateTime.Now;

// 加法
DateTime tomorrow = now.AddDays(1);
DateTime nextHour = now.AddHours(1);
DateTime nextMinute = now.AddMinutes(1);

// 減法
DateTime yesterday = now.AddDays(-1);
DateTime lastWeek = now.AddDays(-7);

// 時間跨度計算
DateTime start = new DateTime(2023, 1, 1);
DateTime end = new DateTime(2023, 12, 31);
TimeSpan duration = end - start; // 364天

// Ticks運算
DateTime preciseTime = now.AddTicks(50000); // 增加5毫秒

比較操作

DateTime dateA = new DateTime(2023, 6, 15);
DateTime dateB = new DateTime(2023, 6, 20);

// 比較方法
int compareResult = DateTime.Compare(dateA, dateB); 
// <0: dateA < dateB
// =0: 相等
// >0: dateA > dateB

// 運算符重載
bool isBefore = dateA < dateB; // true
bool isAfter = dateA > dateB;  // false
bool isSame = dateA == dateB;  // false

// 範圍檢查
bool isInRange = dateA >= start && dateA <= end;

DateTime 與相關類型對比

特性 DateTime DateTimeOffset TimeOnly DateOnly NodaTime
時區支持 強(偏移量)
日期部分 需要計算 需要計算
時間部分
精度 100ns 100ns 100ns 1ns
序列化 有問題 安全 安全 安全 安全
範圍 0001-9999 0001-9999 00:00-24:00 0001-9999 無限
.NET版本 1.0+ 2.0+ 6.0+ 6.0+ NuGet包

最佳實踐總結

存儲原則:

  • 始終以 UTC 時間存儲
  • 僅在顯示時轉換為本地時間

序列化準則:

// 使用ISO 8601格式
DateTime.UtcNow.ToString("O"); // 2023-10-05T06:30:45.1234567Z

時區處理:

  • 使用 DateTimeOffset 替代 DateTime
  • 複雜時區需求使用 NodaTimeTimeZoneInfo

日期/時間分離:

// .NET 6+ 推薦
DateOnly birthday = new DateOnly(1990, 5, 15);
TimeOnly meetingTime = new TimeOnly(14, 30);

性能敏感場景:

  • 避免重複調用 DateTime.Now/UtcNow
  • 預計算靜態日期值
  • 高精度計時用 Stopwatch

資源和文檔

  • DateTime:https://learn.microsoft.com/en-us/dotnet/api/system.datetime
  • TimeZoneInfo:https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo
  • ASP.NET Core:https://learn.microsoft.com/en-us/aspnet/core/
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.