1. 入门
以前在 C# 里没有专门只存日期或者只存时间的类型。所以,就算你只想存个日期——比如生日——也得用 DateTime,还得加个“默认时间”。以前只存日期的老办法就是用 DateTime:
DateTime birthday = new DateTime(1985, 4, 20); // 1985年4月20日,00:00:00
但这样其实挺麻烦的。你明明只想要个日期,结果还带了个时间——虽然是零点,但还是会让人懵圈:比如你比较日期的时候,程序可能会把时间也算进去,结果就很迷。
反过来也一样:如果你只关心时间(比如工作时间 08:00 到 17:00),你还得“编”个日期,其实根本没必要。
现在 .NET 里有了专门的 DateOnly 和 TimeOnly,这些类型直接帮你解决这些乱七八糟的事。
新出的实用类型 DateOnly 和 TimeOnly
- DateOnly —— 只存日历日期,没有时间,也没有时区信息。
- TimeOnly —— 只存一天里的时间,没有年、月、日,也没有时区。
时间类型对比表
| 类型 | 日期 | 时间 | 时区 | 用来干啥? |
|---|---|---|---|---|
|
✅ | ✅ | 🚫 | 几乎啥都能用(但不总是方便和安全) |
|
✅ | ✅ | ✅ | 需要时间点和时区的时候 |
|
✅ | 🚫 | 🚫 | 生日、只要日期不要时间的场景 |
|
🚫 | ✅ | 🚫 | 营业时间、日程表、一天内的时间段 |
2. 玩转 DateOnly
声明和创建
创建 DateOnly 对象就像养成新习惯一样简单!比如:
// 年,月,日
DateOnly birthday = new DateOnly(1985, 4, 20);
用
DateOnly 创建生日日期
如果你已经有了 DateTime 对象,可以用 DateOnly.FromDateTime:
DateTime now = DateTime.Now;
DateOnly today = DateOnly.FromDateTime(now);
// 现在 today 只包含日期,时间被扔掉了
常用属性和方法
- Year、Month、Day —— 跟 DateTime 一样用法。
- .ToString() —— 格式化日期,可以自定义格式。
Console.WriteLine($"生日:{birthday.Year}年,{birthday.Month}月,{birthday.Day}日。");
Console.WriteLine(today.ToString("dd.MM.yyyy")); // 比如 30.07.2024
日期运算
可以很方便地加天/加月/加年:
DateOnly tomorrow = today.AddDays(1);
DateOnly nextMonth = today.AddMonths(1);
试试在你的主项目里,把只存日期的 DateTime 字段都换成 DateOnly —— 你就离现代 .NET 更近一步啦!
日期比较
可以直接用 <、>、== 来比较:
if (birthday < today)
Console.WriteLine("生日已经过了,或者很久以前就过了 :)");
再也不会被多余的毫秒、分钟坑了。
获取今天的日期
DateOnly currentDate = DateOnly.FromDateTime(DateTime.Now);
3. 玩转 TimeOnly
现在来聊聊只存时间不带日期——哪个程序员没遇到过午饭时间表啊?
创建 TimeOnly
TimeOnly startWork = new TimeOnly(9, 0); // 09:00
TimeOnly endWork = new TimeOnly(17, 30); // 17:30
可以只拿小时、分钟、秒:
Console.WriteLine($"工作时间:从 {startWork.Hour}:{startWork.Minute:D2} 到 {endWork.Hour}:{endWork.Minute:D2}");
从 DateTime 获取时间
DateTime now = DateTime.Now;
TimeOnly currentTime = TimeOnly.FromDateTime(now);
Console.WriteLine($"现在是 {currentTime}");
时间运算
TimeOnly breakStart = startWork.AddHours(4); // 4小时后休息,也就是13:00
TimeOnly breakEnd = breakStart.AddMinutes(30); // 午饭30分钟
比较和判断
if (currentTime >= startWork && currentTime <= endWork)
Console.WriteLine("该工作啦 :)");
else
Console.WriteLine("可以休息了。");
4. 和其他类型的互动
DateOnly、TimeOnly 和 DateTime 之间的转换
有时候你还得把它们合成 DateTime(比如老数据库要存,或者要兼容):
DateOnly datePart = new DateOnly(2024, 7, 30);
TimeOnly timePart = new TimeOnly(14, 15);
DateTime datetime = datePart.ToDateTime(timePart); // 2024-07-30 14:15:00
反过来也可以:
DateTime dt = DateTime.Now;
DateOnly justDate = DateOnly.FromDateTime(dt);
TimeOnly justTime = TimeOnly.FromDateTime(dt);
重要细节和常见坑
- 如果你用老方法 DateTime.Parse() 去解析只有日期或只有时间的字符串,大概率会报错或者结果不对。遇到这种情况要用专门的方法:DateOnly.Parse() 和 TimeOnly.Parse() —— 它们知道怎么处理“只要一半”的值。
- 注意:DateOnly 和 TimeOnly 完全不知道啥是时区。它们就是单纯的日期或者时间——跟时区没半毛钱关系。如果你要考虑时区,得自己单独存这玩意儿。
GO TO FULL VERSION