CodeGym /课程 /C# SELF /日期和时间的格式化与解析

日期和时间的格式化与解析

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

1. 日期格式化

如果你觉得输出2025-06-19T17:30:00挺酷的,试试把这种格式给你奶奶或者会计看。他们大概率更喜欢简单点的:19.06.2025 17:30。而说英语的同事会等着06/19/2025 5:30 PM。DevOps和机器最爱2025-06-19T17:30:00Z。所以一个DateTime在内存里,屏幕上能有几十种格式。

反过来也是经典问题:用户在输入框里输个日期("19.06.2025"),你得把它识别成C#对象,还不能搞混哪是天哪是月。自动化、集成、报表——到处都得正确解释文本日期。

基础格式化

C#可以用DateTime、DateOnly、TimeOnly、DateTimeOffset的.ToString()方法把日期/时间对象转成字符串:


DateTime now = DateTime.Now;
Console.WriteLine(now.ToString()); // 输出: 19.06.2025 17:30:25
日期和时间的基础格式化

如果你不传参数给.ToString(),会用系统当前文化的格式(比如德语Windows是一个格式,美式的是另一个)。

标准格式字符串

你可以直接指定输出格式,用所谓的日期和时间标准格式字符串:

格式 说明 输出示例
"d"
短日期 19.06.2025
"D"
完整日期 2025年6月19日
"f"
完整日期+短时间 2025年6月19日 17:30
"F"
完整日期+完整时间 2025年6月19日 17:30:25
"g"
短日期和时间 19.06.2025 17:30
"G"
短日期+完整时间 19.06.2025 17:30:25
"t"
短时间 17:30
"T"
完整时间 17:30:25
"M"/"m"
月和日 6月19日
"Y"/"y"
年和月 2025年6月
"O"/"o"
ISO 8601(round-trip) 2025-06-19T17:30:25.0000000

Console.WriteLine(now.ToString("d")); // 19.06.2025
Console.WriteLine(now.ToString("F")); // 2025年6月19日 17:30:25
Console.WriteLine(now.ToString("O")); // 2025-06-19T17:30:25.0000000

自定义模板

如果你想要更特别的格式,可以用自己的模板:

符号 含义
yyyy 四位数年份
yy 两位数年份
MM 两位数月份
MMMM 月份名称
dd 两位数日期
d 1-2位数日期
HH 小时(24小时制)
mm 分钟
ss 秒
tt AM/PM

Console.WriteLine(now.ToString("yyyy-MM-dd HH:mm")); // 2025-06-19 17:30
Console.WriteLine(now.ToString("dd.MM.yyyy"));       // 19.06.2025
Console.WriteLine(now.ToString("dddd, MMMM d"));     // 星期三, 六月 19

格式化的文化差异

如果你想要别的国家或语言风格的结果,可以用ToString(string, IFormatProvider)重载:


var enUS = new System.Globalization.CultureInfo("en-US");
Console.WriteLine(now.ToString("D", enUS)); // June 19, 2025
  • 如果你死磕模板"MM/dd/yyyy",不管啥文化都会得到"06/19/2025"。
  • 但如果只用"d"或"D",格式就跟文化走!

格式化时要注意的点

格式化日期时要搞清楚标准和自定义格式的区别。标准格式(像"d"、"F"、"G")会自动适配系统文化,适合UI,但系统间数据交换时可能出问题。自定义格式你能完全控制输出,但得自己细调。

特别要注意"O"(或"o")格式——这就是所谓的"round-trip"格式,保证你把日期转成字符串再转回来还是一样的。这个格式在序列化或网络传输时特别重要。

2. 日期和时间的解析:怎么从字符串变对象

最简单的解析:DateTime.Parse

DateTime.Parse——这个方法会按系统文化去识别日期字符串。


string input = "19.06.2025";
DateTime parsed = DateTime.Parse(input);
Console.WriteLine(parsed); // 19.06.2025 00:00:00

如果字符串不对——程序直接抛异常(谁都可能踩坑!)。

指定文化


string input = "06/19/2025";
var enUS = new System.Globalization.CultureInfo("en-US");
DateTime dt = DateTime.Parse(input, enUS);
Console.WriteLine(dt); // 19.06.2025 00:00:00

安全解析:TryParse


string input = "错误的日期";
bool ok = DateTime.TryParse(input, out DateTime safeDate);
if (!ok)
    Console.WriteLine("错误:无法识别日期!");

强制指定格式:ParseExact和TryParseExact


var culture = System.Globalization.CultureInfo.InvariantCulture;
string dateStr = "2025-06-19";

DateTime d = DateTime.ParseExact(dateStr, "yyyy-MM-dd", culture);
Console.WriteLine(d); // 19.06.2025 00:00:00

bool parsedOk = DateTime.TryParseExact(
    "19.06.2025",
    "dd.MM.yyyy",
    System.Globalization.CultureInfo.InvariantCulture,
    System.Globalization.DateTimeStyles.None,
    out DateTime myDate);

常见格式表

字符串 格式 最终对象
"2025-06-19" "yyyy-MM-dd" 2025年6月19日
"19.06.2025" "dd.MM.yyyy" 2025年6月19日
"06/19/2025" "MM/dd/yyyy" 2025年6月19日
"2025-06-19T14:15:16" "s" 2025年6月19日 14:15:16

用DateTimeStyles解析

解析时你还可以用DateTimeStyles参数来控制行为。这个enum能让你定制解析器怎么理解输入。比如DateTimeStyles.AssumeUniversal会让解析器把时间当UTC(如果没写偏移),DateTimeStyles.AllowWhiteSpaces能忽略字符串里的多余空格。这些设置在处理外部数据时特别有用,因为格式可能很飘忽。

3. DateOnly和TimeOnly的格式化和解析

新的DateOnly和TimeOnly类型现在经常用来存日期/时间,不带多余细节。

格式化


DateOnly birthday = new DateOnly(2000, 6, 19);
Console.WriteLine(birthday.ToString("dd MMMM yyyy")); // 2000年6月19日

解析


var d = DateOnly.ParseExact("19.06.2000", "dd.MM.yyyy");
Console.WriteLine(d.Day); // 19

TimeOnly的方法也是一样(只是模板只管小时/分钟/秒):

TimeOnly t = TimeOnly.ParseExact("23:59", "HH:mm");
Console.WriteLine(t.Hour); // 23

DateOnly和TimeOnly的优点

用DateOnly和TimeOnly代替DateTime有几个好处。第一,语义更清晰——你只要日期不用时间(比如生日),DateOnly就很直观。第二,能避免DateTime常见的时区坑。第三,这些类型占内存和数据库空间更小。

带时区的格式化和解析

如果你要存带偏移的信息——用DateTimeOffset。这对国际化、分布式系统特别重要。所有格式化和解析方法都一样,只是现在还能管偏移量:


DateTimeOffset meeting = new DateTimeOffset(2025, 6, 19, 17, 30, 0, TimeSpan.FromHours(3));
Console.WriteLine(meeting.ToString("o")); // 2025-06-19T17:30:00.0000000+03:00

string input = "2025-06-19T17:30:00+03:00";
var parsedOffset = DateTimeOffset.Parse(input);
Console.WriteLine(parsedOffset.Offset); // 03:00:00

4. 实用建议和常见错误

一个大坑——解析国际格式时把“天”和“月”搞混。比如"01/02/2025"在美国是1月2日,在大多数欧洲国家是2月1日(惊不惊喜!)。

还有经常忘了文化影响:如果你的应用跑在德国服务器上,用户来自不同国家,数据库里的日期格式在每台服务器上解释都可能不一样。

常见错误——日志和数据交换文件里用.ToString()不指定文化/格式:换个操作系统或者不同Windows用户,结果就变了。

日期处理建议

  • 内部存储和数据交换时总用不变文化(CultureInfo.InvariantCulture)或明确指定格式。
  • UI用用户文化,或者让用户选喜欢的格式。
  • 和API、数据库打交道时优先用ISO 8601格式,这可是国际标准。
  • 总要校验输入数据:检查日期是否存在、范围和合理性。

和不同数据源打交道

跟外部系统集成时,经常会遇到各种格式的日期。有的系统用Unix timestamp(从1970年1月1日到现在的秒数),有的用本地格式的字符串。一定要提前约定好数据交换格式,并且每次都校验解析结果。

还要记住,有些格式可能有歧义。比如"12/13/2025"肯定是2025年12月13日,但"12/11/2025"可能是11月12日,也可能是12月11日,得看文化。这种情况最好用不容易混淆的格式,或者明确指定解析文化。

2
任务
C# SELF, 第 15 级, 课程 3
已锁定
基础日期和时间格式化
基础日期和时间格式化
2
任务
C# SELF, 第 15 级, 课程 3
已锁定
安全地从字符串解析日期
安全地从字符串解析日期
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION