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 与相关类型对比

特性DateTimeDateTimeOffsetTimeOnlyDateOnlyNodaTime
时区支持强(偏移量)
日期部分需要计算需要计算
时间部分
精度100ns100ns100ns1ns
序列化有问题安全安全安全安全
范围0001-99990001-999900:00-24:000001-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/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值