CodeGym /课程 /C# SELF /处理时间的基本类型

处理时间的基本类型

C# SELF
第 15 级, 课程 0
可用

1. 认识 DateTime 类型

日期和时间——这是任何业务逻辑的基础砖头,哪怕是最简单的项目也不能忽略。有时候你得知道用户啥时候注册的,啥时候发邮件,航班表怎么排,时区怎么搞——到处都是日期!但说实话,处理日期和时间是编程里最坑的主题之一。😅

C#给你两个特别重要的时间类型:DateTime 和 DateTimeOffset。简单说,一个适合简单场景,另一个适合涉及时区和精确时间存储的任务。

DateTime 是啥?

DateTime 类型是个结构体,定义在 System 命名空间里。它用来存储日期和时间,精确到100纳秒(十亿分之一秒)。

  • 值类型(struct),也就是按值复制。
  • 同时包含日期和时间。
  • 可以只存日期(2025-05-24),也可以存日期加时间(2025-05-24 15:17:42)。
  • “不知道”时区,除非你明确指定。

2. 创建 DateTime

有好几种方式,咱们挑主要的说。

1. 当前日期和时间

DateTime now = DateTime.Now;           // 电脑本地时间
DateTime utcNow = DateTime.UtcNow;     // 格林威治时间(UTC)
  • Now —— 就是“你电脑上的时间”,带着Windows本地时区。
  • UtcNow —— “通用时间”,也就是世界协调时间。存数据库或者全球系统用这个很方便。

2. 构造函数

// 年,月,日
var date1 = new DateTime(2025, 5, 24);

// 年,月,日,小时,分钟,秒
var date2 = new DateTime(2025, 5, 24, 12, 0, 0);

// 年,月,日,小时,分钟,秒,毫秒
var date3 = new DateTime(2025, 5, 24, 12, 0, 0, 500);

月份不是从0开始的! 也就是说一月是1,十二月是12。

3. 从字符串解析

经常日期是字符串形式来的!比如用户手动输入日期。

string userInput = "2025-05-24 18:30";
DateTime parsed = DateTime.Parse(userInput); // 可能会抛异常!

想安全点解析——用 TryParse:

string input = "2025-05-24 18:30";
if (DateTime.TryParse(input, out DateTime result))
{
    Console.WriteLine($"转换成功: {result}");
}
else
{
    Console.WriteLine("字符串转日期失败。");
}

4. 获取“只有日期”的DateTime

DateTime today = DateTime.Today; // 今天,时间是00:00:00

提取日期和时间的组成部分

所有属性都能直接拿到:

var dt = new DateTime(2025, 5, 24, 15, 17, 42);

int year = dt.Year;         // 2025
int month = dt.Month;       // 5(五月)
int day = dt.Day;           // 24
int hour = dt.Hour;         // 15
int minute = dt.Minute;     // 17
int second = dt.Second;     // 42
DayOfWeek dow = dt.DayOfWeek; // 星期五

3. 用 DateTime 干活

日期加减

时间在编程里过得飞快,别自己算“离deadline还有几小时”,直接用类的方法:

DateTime now = DateTime.Now;
DateTime tomorrow = now.AddDays(1); // 明天
DateTime afterFiveHours = now.AddHours(5); // 5小时后
DateTime inTenMinutes = now.AddMinutes(10); // 10分钟后

两个日期的差值:TimeSpan

两个日期的差值是个独立的类型,叫 TimeSpan:

DateTime deadline = new DateTime(2026, 6, 1);
DateTime now = DateTime.Now;

TimeSpan untilDeadline = deadline - now;

Console.WriteLine($"离截止还有天数: {untilDeadline.Days}");
Console.WriteLine($"离截止还有小时: {untilDeadline.TotalHours:N2}");

TimeSpan 是“差值”,不是“具体的日期/时间”!

判断日期是未来还是过去

if (deadline > now)
    Console.WriteLine("截止还没到!");
else
    Console.WriteLine("截止已经过了!赶紧交作业!");

4. 日期在底层是怎么存的

为了方便日期加减,程序员决定把所有日期都存成从公元元年开始经过的秒数。取值范围如下:

属性 值
最小日期
DateTime.MinValue
= 0001-01-01 00:00:00
最大日期
DateTime.MaxValue
= 9999-12-31 23:59:59.9999999
单位 1 tick = 100纳秒

DateTime 存的不是秒数,而是“tick”数(ticks),从特殊的日期——公元0001年1月1日(没错,程序员不管恐龙,纪年更严谨)开始。一个tick=100纳秒。

5. DateTimeOffset 类型

有时候 DateTime 不够用。举个经典例子:公司在两个国家有业务,时区不同,所有会议都按“我的时间”定。咋办?

用 DateTime 存的时间其实是“抽象的”:就是一串数字和tick,除非你明确说这是哪个时区。比如你拿到"2025-05-24 15:00",你根本不知道——这是内罗毕时间?巴格达?柏林?(要是还有夏令时,头都大了!)

所以,涉及精确时刻的任务,不只是“日历上的日期”,就有了第二种类型——DateTimeOffset。创建 DateTimeOffset 时可以指定偏移量(比如内罗毕比UTC快3小时):


var localTime = new DateTimeOffset(2025, 5, 24, 15, 0, 0, TimeSpan.FromHours(3));

如果你遇到这些情况,就用 DateTimeOffset:

  • 需要精确时刻(比如日志事件,和服务器时间绑定)。
  • 程序有不同时区的用户。
  • 要存/传带时区的时间(比如交易、事件、日程)。

6. 怎么创建 DateTimeOffset?

  1. 当前时刻
    DateTimeOffset now = DateTimeOffset.Now; // 本地时间+偏移
    DateTimeOffset utc = DateTimeOffset.UtcNow; // UTC(偏移0)
    
  2. 手动创建
    // 年,月,日,小时,分钟,秒,偏移(比如+2小时)
    DateTimeOffset custom = new DateTimeOffset(2025, 5, 24, 20, 0, 0, TimeSpan.FromHours(2));
    
  3. 从DateTime转换
    DateTime dt = DateTime.Now;
    DateTimeOffset dto = new DateTimeOffset(dt); // 自动带上本地偏移
    

提取组成部分

DateTimeOffset dto = DateTimeOffset.Now;
var datePart = dto.Date;      // 只有日期
var timePart = dto.TimeOfDay; // 只有时间
var offset = dto.Offset;      // 相对UTC的偏移,比如03:00:00

时区之间的转换

偏移的魔法:

// 拿到UTC时间
var now = DateTimeOffset.Now;
var utc = now.ToUniversalTime();
Console.WriteLine(utc); // 格林威治时间

// 转到另一个时区
var berlinTime = utc.ToOffset(TimeSpan.FromHours(2));
Console.WriteLine(berlinTime); // 柏林时间(CET +2)

7. 什么时候用 DateTime,什么时候用 DateTimeOffset?

选择哲学

如果只是简单本地的事——比如生日、文章发布时间、问卷截止到15:00,通常用 DateTime 就够了。这种场景绝对时间不重要,只要事件发生在某天某小时就行,不用管时区。

但如果你要记录精确时刻,带时区,比如日志、交易、分布式系统——最好用 DateTimeOffset。这样跨系统传时间不会乱,尤其是不同地区的系统。

场景 类型 理由
生日
DateTime
只关心日期,不关心时区(通常)
登录时间
DateTimeOffset
要知道精确时刻和偏移
商品有效期
DateTime
截止日期,不关心时区
日志事件时间
DateTimeOffset
最好总是带偏移存
2
任务
C# SELF, 第 15 级, 课程 0
已锁定
以不同格式输出当前日期和时间
以不同格式输出当前日期和时间
2
任务
C# SELF, 第 15 级, 课程 0
已锁定
时间的加减
时间的加减
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION