在 .NET 开发中,DateTime
是我们最常用的结构之一,用于表示一个具体的日期和时间点。无论是记录创建时间、判断是否过期,还是做定时任务,都绕不开它。
一、DateTime 是什么?
public struct DateTime : IComparable, IFormattable, IConvertible, ISerializable, IComparable<DateTime>, IEquatable<DateTime>
-
DateTime
是一个结构体,表示一个精确到 100 纳秒的时间点。 -
它的最小值是
0001-01-01 00:00:00
,最大值是9999-12-31 23:59:59
。 -
一秒等于十亿纳秒(10,0000,0000)
二、常用获取方式
1. 获取当前本地时间
DateTime now = DateTime.Now;
-
Now
返回当前系统的本地时间,受时区影响。 -
依赖操作系统的时钟。
2. 获取当前 UTC 时间
DateTime utcNow = DateTime.UtcNow;
-
UtcNow
返回协调世界时(UTC),不受本地时区影响。 -
是跨地区应用推荐使用的时间源。
3. 今天零点
DateTime today = DateTime.Today; // 今天 00:00:00
三、Now 和 UtcNow 的区别
特性 | DateTime.Now | DateTime.UtcNow |
---|---|---|
是否受时区影响 | 是 | 否 |
显示是否直观 | 是(适合用户界面) | 否 |
跨时区是否安全 | 否 | 是 |
用于日志存储 | 不推荐 | 推荐 |
建议:计算和存储用 UtcNow
,展示给用户时再转为本地时间。
四、Ticks
1.什么是 Tick?
在 .NET 中:
1 Tick = 100 纳秒(即 0.0000001 秒)
这意味着:
-
1 毫秒 = 10,000 ticks
-
1 秒 = 10,000,000 ticks(十亿除以一百得到一千万,可以打印 DateTime.MinValue.AddSeconds(1).Ticks验证)
DateTime.Ticks
是一个 long
类型,表示自 0001-01-01 00:00:00
(公元 1 年 1 月 1 日)以来经过的 Tick 数。
cs
DateTime dt = new DateTime(2025, 8, 7);
Console.WriteLine(dt.Ticks); // 输出:638536704000000000(具体数值因时间不同而变化)
2.DateTime.MaxValue
的极限是多少?
在 .NET 中,DateTime
的最大值是:
DateTime max = DateTime.MaxValue;
Console.WriteLine(max); // 9999-12-31 23:59:59.9999999
Console.WriteLine(max.Ticks); // 3155378975999999999
换句话说,DateTime
可以精确表示的最晚时刻是:
9999-12-31 23:59:59.9999999(共 7 位小数,单位是 100 纳秒)
这个时间点的 Ticks
值是 3,155,378,975,999,999,999
,也就是自公元 0001 年 1 月 1 日 00:00:00 起,经过的 100 纳秒单位的总数。
虽然这个值已经很大,但它只是 long.MaxValue
的约 34% 左右(long.MaxValue
是 9,223,372,036,854,775,807
),因此仍有非常大的冗余空间,不会发生溢出。
3.为什么选择 9999 年?
这是出于兼容性和文化意义的考虑:
-
很多数据库(如 SQL Server)同样以 9999 年为上限。
-
人类可预见范围内的日期都可以包含。
-
如果允许更大年份,会影响解析、显示、格式化的性能与实现。
4.小结
属性 | 值 |
---|---|
最小时间 | 0001-01-01 00:00:00.0000000 |
最大时间 | 9999-12-31 23:59:59.9999999 |
每 Tick 间隔 | 100 纳秒(0.0000001 秒) |
最大 Ticks 值 | 3155378975999999999 |
Ticks 类型 | long (Int64) |
是否撑爆了? | 没有。离爆炸还差得远。 |
五、系统时间是从哪来的?
1.操作系统维护的系统时钟
DateTime.Now
和 DateTime.UtcNow
都来自操作系统:
-
Windows 会维护一个系统时间(通常为 UTC),并通过 API 提供本地时间或 UTC。
-
这个系统时间来源于:
-
主板上的实时时钟(RTC)
-
网络时间同步(NTP)
-
用户手动修改
-
也就是说,可以通过手动或编程方式修改系统时间,影响 DateTime
的表现。
2.更改系统时间:
-
控制面板 → 日期和时间 → 更改时间(手动)
-
使用代码(需要管理员权限)调用
SetSystemTime
API -
Linux 系统用
date
命令:sudo date -s "2025-08-07 12:00:00"
例如 C# 调用 API 修改系统时间:
[DllImport("kernel32.dll")]
static extern bool SetSystemTime(ref SYSTEMTIME st);
修改系统时间会影响所有基于 DateTime.Now
的逻辑,包括任务调度、日志记录、缓存过期、证书验证等。
六、DateTime 常用 API
🕒 1. 获取当前时间
DateTime now = DateTime.Now; // 本地时间
DateTime utcNow = DateTime.UtcNow; // UTC 时间
DateTime today = DateTime.Today; // 当天 00:00:00
🏗 2. 构造 DateTime
var dt1 = new DateTime(2025, 8, 7); // 只指定日期,时间默认为 00:00:00
var dt2 = new DateTime(2025, 8, 7, 14, 30, 0); // 精确到时分秒
📅 3. 获取组成部分
int year = dt2.Year;
int month = dt2.Month;
int day = dt2.Day;
int hour = dt2.Hour;
int minute = dt2.Minute;
int second = dt2.Second;
DayOfWeek dayOfWeek = dt2.DayOfWeek;// 返回表示星期几的枚举值(如 DayOfWeek.Monday)
int dayOfYear = dt2.DayOfYear;// 返回该日期是一年中的第几天(范围 1 ~ 366)
TimeSpan timeOfDay=dt2.TimeOfDay;//返回一个时间间隔,意思是今天已经过了多久
一打印dayOfYear,忽然发现2025一眨眼就过了200多天了 忽忽悠悠今年又快过去了!
➕ 4. 加减时间
DateTime tomorrow = DateTime.Now.AddDays(1);
DateTime nextMonth = DateTime.Now.AddMonths(1);
DateTime oneHourLater = DateTime.Now.AddHours(1);
DateTime fiveMinutesAgo = DateTime.Now.AddMinutes(-5);
⏱ 5. 计算时间差(TimeSpan)
TimeSpan diff = dt2 - dt1;
double totalDays = diff.TotalDays;
double totalSeconds = diff.TotalSeconds;
🔁 6. 比较时间
bool isEarlier = dt1 < dt2;
bool isSame = dt1 == dt2;
int result = DateTime.Compare(dt1, dt2);
// result < 0 表示 dt1 早于 dt2
// result == 0 表示相等
// result > 0 表示 dt1 晚于 dt2
🔤 7. 格式化时间字符串
string s1 = dt1.ToString("yyyy-MM-dd"); // 2025-08-07
string s2 = dt1.ToString("yyyy-MM-dd HH:mm:ss"); // 2025-08-07 00:00:00
string s3 = dt1.ToString("dddd"); // 星期几
cs
DateTime currentDateTime = DateTime.Now;
var culture = new CultureInfo("zh-CN");
string formattedDate = currentDateTime.ToString("yyyy年M月d日 dddd HH:mm:ss", culture);
注意:格式字符串是区分大小写的。
📥 8. 解析时间字符串
DateTime parsed = DateTime.Parse("2025-08-07");
DateTime parsed2 = DateTime.ParseExact("07-08-2025", "dd-MM-yyyy", null);
bool success = DateTime.TryParse("invalid", out DateTime dt); // 不抛异常
🧮 9. 其他有用属性
bool isLeapYear = DateTime.IsLeapYear(2024); // 闰年判断
int daysInMonth = DateTime.DaysInMonth(2025, 2); // 某月天数
🔢 10. 时间戳转换(Unix 时间)
DateTimeOffset dto = DateTimeOffset.UtcNow;
long unixTimestamp = dto.ToUnixTimeSeconds(); // 秒级时间戳
long millis = dto.ToUnixTimeMilliseconds(); // 毫秒级时间戳
DateTimeOffset fromUnix = DateTimeOffset.FromUnixTimeSeconds(unixTimestamp);
📚 11. Ticks 与精度
long ticks = dt1.Ticks; // 100 纳秒为单位的"时间刻度"
DateTime fromTicks = new DateTime(ticks);