C#中DateTime与TimeSpan相加出现额外12小时问题求助
问题原因与解决方案
为什么会出现额外的12小时?
核心问题出在你用DateTime(日期时间点)来存储和累加时间段,这完全用错了类型!
DateTime.ParseExact解析"00:00:30"这种字符串时,会默认把它绑定到公元1年1月1日这个日期上,对应的时间点是0001-01-01 00:00:30。当你用"hh:mm:ss"格式化这个时间点时,hh是12小时制的格式符,午夜0点在12小时制里会被显示为12——这就是为什么你得到12:00:40的原因,本质是把凌晨0点的时间点当成了12小时制的午夜12点来显示。
另外,你把时间段存在文本框里再反复解析成DateTime的做法,本身就违背了类型设计的初衷:TimeSpan才是专门用来表示时间长度/时间段的类型,DateTime是用来表示具体的日期时间点的,两者不能混用。
怎么修复?
直接改用TimeSpan来存储累加的总时长,代码逻辑会清晰很多,也不会出现奇怪的格式化问题:
- 首先在你的窗体类里声明一个类级别的变量,用来保存累计时长:
// 初始化为0时长 private TimeSpan _totalElapsedTime = TimeSpan.Zero;
- 修改
stopbutton_Click方法的逻辑,直接用TimeSpan累加,避免解析DateTime的坑:
public void stopbutton_Click(object sender, EventArgs e) { stopTime.Text = DateTime.Now.ToString("hh:mm:ss"); // 解析开始和结束时间为DateTime,这部分没问题 DateTime dt1 = DateTime.ParseExact(startTime.Text, "hh:mm:ss", new DateTimeFormatInfo()); DateTime dt2 = DateTime.ParseExact(stopTime.Text, "hh:mm:ss", new DateTimeFormatInfo()); TimeSpan ts1 = dt2.Subtract(dt1); // 显示单次耗时,用TimeSpan的格式化字符串,避免歧义 diffTime.Text = ts1.ToString(@"hh\:mm\:ss"); // 直接累加总时长 _totalElapsedTime += ts1; // 格式化显示总时长: // 如果总时长不会超过24小时,直接用TimeSpan的格式化 totTime.Text = _totalElapsedTime.ToString(@"hh\:mm\:ss"); // 如果需要支持超过24小时的累计(比如总时长25:30:00),用下面的写法: // totTime.Text = $"{(int)_totalElapsedTime.TotalHours:D2}:{_totalElapsedTime.Minutes:D2}:{_totalElapsedTime.Seconds:D2}"; }
额外说明
@"hh\:mm\:ss"是TimeSpan的正确格式化方式,因为:在格式化字符串里是特殊字符,需要转义;- 如果你的累计时长可能超过24小时,直接用
TimeSpan.ToString(@"hh\:mm\:ss")只会显示0-23的小时数,这时候需要用TotalHours来获取累计的总小时数,再拼接分钟和秒; - 不要再用
DateTime来处理时间段了,这会让你陷入各种日期和12/24小时制的坑,TimeSpan就是为这种场景而生的。
内容的提问来源于stack exchange,提问作者user13965861
相关产品推荐
相关产品推荐

