如何避免DateTime.Now赋值多变量时的Ticks差异问题
看起来你遇到的核心问题是DateTime的高精度Ticks在对比时引发误判——虽然日期、时、分、秒都完全匹配,但因为原始DateTime.Now包含毫秒甚至更细的精度,而后续表单生成的_eventItem.StartDateTime可能丢失了这部分精度,导致直接对象对比时判定为不相等。
先澄清一个关键细节:C#里的DateTime是值类型,直接赋值(比如_uneditedEvent.StartDateTime = _eventStartDate)就会完整复制所有属性(包括Ticks),所以你初始化时的_uneditedEvent和_eventStartDate的Ticks肯定是完全一致的,问题不在复制环节,而是出在后续_eventItem的日期时间生成逻辑上。
下面给你几个可行的解决方案:
方案1:统一日期时间精度,截断到秒(或你需要的粒度)
从源头统一日期时间的精度,去掉毫秒及以下的部分,这样对比时就不会因为微小的Ticks差异导致误判。
修改初始化代码:
var startDate = DateTime.Now; // 截断到秒,去除毫秒及更细的精度 var truncatedStartDate = startDate.AddTicks(-(startDate.Ticks % TimeSpan.TicksPerSecond)); var endDate = truncatedStartDate.AddHours(1); var truncatedEndDate = endDate.AddTicks(-(endDate.Ticks % TimeSpan.TicksPerSecond)); _eventStartDate = truncatedStartDate; _eventEndDate = truncatedEndDate; _uneditedEvent = new EventItem() { StartDateTime = _eventStartDate, EndDateTime = _eventEndDate, };
同时,当用户在表单中选择日期时间后,生成_eventItem.StartDateTime和_eventItem.EndDateTime时,也要做同样的截断处理,确保两边的精度完全一致。
方案2:对比时忽略高精度差异,只校验到关心的级别
如果不想修改日期时间的生成逻辑,可以在对比时跳过Ticks的高精度部分,只校验你真正关心的年、月、日、时、分、秒。
可以封装一个辅助方法:
bool AreDateTimeEqual(DateTime dt1, DateTime dt2) { return dt1.Year == dt2.Year && dt1.Month == dt2.Month && dt1.Day == dt2.Day && dt1.Hour == dt2.Hour && dt1.Minute == dt2.Minute && dt1.Second == dt2.Second; }
然后修改你的校验条件:
if (_uneditedEvent.Type != _eventItem.Type || _uneditedEvent.CustomerCode != _eventItem.CustomerCode || _uneditedEvent.ProjectCode != _eventItem.ProjectCode || !AreDateTimeEqual(_uneditedEvent.StartDateTime, _eventItem.StartDateTime) || !AreDateTimeEqual(_uneditedEvent.EndDateTime, _eventItem.EndDateTime) || _uneditedEvent.Notes != _eventItem.Notes) { var action = await _pageDialogue.DisplayAlertAsync("Unsaved Changes", "Do you want to abandon this event?", "Yes", "No"); switch (action) { case false: return; } }
或者用更简洁的方式,通过时间差判断:
Math.Abs((_uneditedEvent.StartDateTime - _eventItem.StartDateTime).TotalSeconds) < 1
方案3:使用DateTimeOffset替代DateTime(可选)
如果你的场景涉及时区,DateTimeOffset比DateTime更可靠,对比逻辑也更清晰,同样可以用上面的精度截断或差异判断方式处理。
总结一下,你的问题本质不是复制DateTime的问题(C#值类型赋值已经是完整复制),而是高精度Ticks在表单交互后丢失导致的对比不匹配,上面的方案都能解决问题,推荐方案1,从源头统一精度,彻底避免后续的对比隐患。
内容的提问来源于stack exchange,提问作者Bodungus

