DateTime
在 .NET 框架中,DateTime 是 System 命名空间下用于表示日期与时间的核心结构体,广泛应用于各种时间相关的操作场景,如时间的存储、计算、格式化以及与其他时间格式之间的转换。
System
System.DateTime
DateTime 是一个值类型(struct),其内部通过“刻度”(ticks)来表示时间点。每个 tick 等于 100 纳秒,从公元 0001 年 1 月 1 日午夜 00:00:00 开始计数。
struct
DateTime.MinValue
该结构包含两个核心组成部分:
long 类型的 ticks 值,记录自起始时间以来经过的时间单位;DateTimeKind 枚举值,标识该时间的时区类别:long
DateTimeKind
Unspecified
UTC
Utc
Local
有效时间跨度为:
DateTime.MinValue → 0001-01-01 00:00:00DateTime.MaxValue → 9999-12-31 23:59:59.9999999DateTime.MinValue
DateTime.MaxValue
1 秒 = 10,000,000 Ticks 1 毫秒 = 10,000 Ticks 1 分钟 = 600,000,000 Ticks
DateTime 可精确表示年、月、日、时、分、秒及毫秒,并提供相应属性进行访问。同时支持 Kind 属性以区分时间类型。
Kind
Utc、Local、Unspecified
DateTime 实例进行比较;AddDays, AddHours, AddMinutes 等方法);TimeSpan 对象。Compare、CompareTo
AddDays、AddHours
Subtract
TimeSpan
借助 ToString() 方法和标准或自定义格式字符串,实现灵活的时间格式化显示,例如:
dt.ToString("yyyy-MM-dd HH:mm:ss")
ToString
"yyyy-MM-dd HH:mm:ss"
此外,还支持根据不同的区域性(CultureInfo)进行本地化格式输出。
CultureInfo
支持与多种时间表示形式相互转换,包括:
Parse, TryParse);Unix
DateTime.Now:获取当前本地时间;DateTime.UtcNow:获取当前 UTC 时间;DateTime.Today:获取当前日期,时间部分归零(即 00:00:00)。DateTime.Now
DateTime.UtcNow
UTC
DateTime.Today
| 属性名 | 说明 |
|---|---|
DateTime.Now |
返回当前本地时区的日期和时间 |
DateTime.UtcNow |
返回当前的协调世界时(UTC) |
DateTime.Today |
返回今天的日期,时间设为 00:00:00 |
Date |
提取当前实例的日期部分,时间归零 |
Year, Month, Day |
分别获取年、月、日 |
Hour, Minute, Second, Millisecond |
获取对应的时间组成部分 |
DayOfWeek |
返回星期几的枚举值(如 Monday, Tuesday...) |
DayOfYear |
返回该日期在当年中的第几天(范围:1–366) |
Kind |
指示时间种类(Unspecified / Utc / Local) |
Ticks |
返回自 0001-01-01 00:00:00 起经过的 tick 数(每 tick 为 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); // 同时指定 DateTimeKind var dt2 = new DateTime(2025, 8, 8, 14, 30, 0, DateTimeKind.Utc); // 从 ticks 构造 var dtTicks = new DateTime(637632000000000000L);
// 将 Unix 时间戳(秒)转换为 DateTime(UTC) var unixEpoch = DateTimeOffset.FromUnixTimeSeconds(0).UtcDateTime; // 当前 UTC 时间转为 Unix 时间戳(秒) long toUnix = ((DateTimeOffset)DateTime.UtcNow).ToUnixTimeSeconds();
DateTimeOffset 更适合处理跨时区应用,因为它不仅包含时间点,还显式保存了相对于 UTC 的偏移量,避免了因 DateTime.Kind 不明确而导致的问题。
DateTimeOffset
推荐在涉及全球化或多时区逻辑时优先使用 DateTimeOffset,而非依赖 DateTime 的 Kind 属性进行推断。
Kind
var dto = new DateTimeOffset(dt); // 使用本地时区偏移 var dtoUtc = new DateTimeOffset(dt, TimeSpan.Zero); // 强制设置为 UTC 偏移
DateTime
DateTime today = DateTime.Today; // 获取今日零点时间 DateTime min = DateTime.MinValue; // 最小时间值(0001-01-01) DateTime max = DateTime.MaxValue; // 最大时间值(9999-12-31) DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); // Unix 时间起点
public enum DateTimeKind
{
Unspecified = 0, // 未指定时区(默认值)
Utc = 1, // 表示 UTC 时间
Local = 2 // 表示本地时区时间
}
正确设置 Kind 对于避免时区混淆至关重要,特别是在序列化、反序列化或跨系统传递时间数据时。
通过 DateTime 对象的属性,可以方便地获取时间的各个组成部分:
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 + ...
| 格式符 | 说明 | 示例输出 |
|---|---|---|
| "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"); // 星期几, 月 日 年
使用 .NET 提供的方法可以从字符串还原为 DateTime 对象。
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);
在处理跨时区应用时,正确管理时区信息至关重要。以下是一些常见操作的实现方式:
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);
在处理日期时,.NET 提供了多种方法来获取特定信息。例如:
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 实例中提取出星期几、一年中的第几天等信息:
DayOfWeek dayOfWeek = dt.DayOfWeek; // DayOfWeek.Thursday
int dayOfYear = dt.DayOfYear; // 278(表示2023年10月5日是该年的第278天)
支持对时间进行加减操作,包括天数、小时、分钟等单位:
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);
还可以通过 Ticks 进行更高精度的操作:
// 增加5毫秒(每毫秒等于10,000个Ticks)
DateTime preciseTime = now.AddTicks(50000);
计算两个日期之间的时间跨度:
DateTime start = new DateTime(2023, 1, 1);
DateTime end = new DateTime(2023, 12, 31);
TimeSpan duration = end - start; // 相差364天
可以使用 Compare 方法或重载的操作符来进行日期比较:
DateTime dateA = new DateTime(2023, 6, 15);
DateTime dateB = new DateTime(2023, 6, 20);
// 使用静态 Compare 方法
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 | DateTimeOffset | TimeOnly | DateOnly | NodaTime |
|---|---|---|---|---|---|
| 时区支持 | 弱 | 强(含偏移量) | 无 | 无 | 强 |
| 日期部分 | 需要计算提取 | 需要计算提取 | 无 | 有 | 有 |
| 时间部分 | 有 | 有 | 有 | 无 | 有 |
| 精度 | 100纳秒 | 100纳秒 | 100纳秒 | 天级 | 1纳秒 |
| 序列化安全性 | 存在问题 | 安全 | 安全 | 安全 | 安全 |
| 有效范围 | 0001-9999年 | 0001-9999年 | 00:00-24:00 | 0001-9999年 | 无限 |
| .NET 版本要求 | 1.0+ | 2.0+ | 6.0+ | 6.0+ | NuGet 包 |
推荐始终以 UTC 时间进行数据存储,在展示给用户时再转换为本地时间。
UTC
为确保跨平台兼容性,建议使用 ISO 8601 标准格式进行序列化:
// 示例:输出标准UTC时间字符串
DateTime.UtcNow.ToString("O"); // 如:2023-10-05T06:30:45.1234567Z
对于简单的时区偏移场景,应优先使用:
DateTimeOffset
替代传统的不带偏移量类型:
DateTime
若涉及复杂的时区规则(如夏令时),推荐采用:
NodaTime
或
TimeZoneInfo
从 .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.datetimeTimeZoneInfoASP.NET Core 是一个开源的高性能框架,用于构建现代云端集成的应用程序。它支持跨平台开发,允许开发者在 Windows、Linux 和 macOS 上构建和运行应用。该框架适用于微服务架构、Web 应用、API 以及实时通信应用等多种场景。
通过 ASP.NET Core,开发者可以利用依赖注入、配置管理、日志记录等内置功能,提升开发效率并增强应用的可维护性。此外,它与 .NET 运行时深度集成,能够充分发挥 .NET 生态系统的优势。
ASP.NET Core
System.TimeZoneInfo 类是 .NET 中用于表示任意时区的时间信息的类。它提供了将时间在不同时区之间进行转换的能力,支持夏令时规则,并允许应用程序处理全球范围内的本地时间。该类可用于获取系统已定义的时区,也可创建自定义时区。
开发者可以通过 TimeZoneInfo.FindSystemTimeZoneById 方法根据 ID 获取特定时区,并使用 ConvertTime 方法实现时间的跨时区转换。此功能对于需要处理多地区用户时间数据的应用(如日历、调度系统)尤为重要。
扫码加好友,拉您进群



收藏
