C#中DateTime仅改时分及Kendo UI TimePicker日期篡改问题求解
嘿,这个问题我用Kendo UI做表单的时候也踩过坑,刚好有几个可行的解决方案,给你梳理下:
Kendo的TimePicker默认会用它内部的默认日期(就是你碰到的2018/01/03这类)填充日期字段,但我们可以通过绑定逻辑和事件处理,强制保留ViewModel里的原始日期:
绑定初始值时保留完整DateTime:
给TimePicker设置format: "HH:mm"让它只显示时分,但绑定的是完整的DateTime对象,而不是转成纯时间字符串。这样用户看到的是时分,但底层还是关联着原始的日期信息。在Change事件里实时合并日期和时间:
当用户选完新时间后,在change事件里把原始日期和新时间拼起来,覆盖掉TimePicker自动生成的日期。举个代码例子:$("#startTimePicker").kendoTimePicker({ format: "HH:mm", // 初始值绑定完整的DateTime value: new Date("@Model.StartTime.ToString("yyyy-MM-ddTHH:mm:ss")"), change: function(e) { // 从ViewModel或隐藏字段拿到原始的完整日期时间 const originalDateTime = new Date("@Model.StartTime.ToString("yyyy-MM-ddTHH:mm:ss")"); // 获取用户刚选的时间部分 const selectedTime = this.value(); // 合并原始日期 + 新时间 const mergedDateTime = new Date( originalDateTime.getFullYear(), originalDateTime.getMonth(), originalDateTime.getDate(), selectedTime.getHours(), selectedTime.getMinutes() ); // 更新绑定的ViewModel字段,同时把合并后的值设回TimePicker viewModel.StartTime = mergedDateTime; this.value(mergedDateTime); } });这样用户操作的时候,日期部分就不会被莫名其妙改掉了。
如果觉得前端事件处理有点繁琐,你说的加oldStartTime这类属性的思路完全可行,而且更稳妥:
ViewModel里加原始日期属性:
页面加载时,把StartTime的完整值复制到OldStartTime(类型也是DateTime),这样原始的年月日就被存下来了。提交时合并日期和新时间:
不管TimePicker返回的DateTime日期部分是什么,我们都用OldStartTime的日期,加上用户选的时分生成最终的时间:// 后台处理提交的ViewModel时 var originalDate = model.OldStartTime.Date; var newTime = model.StartTime.TimeOfDay; model.StartTime = originalDate.Add(newTime);如果是前端AJAX提交,逻辑类似:
const originalDate = new Date(viewModel.OldStartTime); const newTime = new Date(viewModel.StartTime); viewModel.StartTime = new Date( originalDate.getFullYear(), originalDate.getMonth(), originalDate.getDate(), newTime.getHours(), newTime.getMinutes() ); // 然后提交viewModel
要是不想给ViewModel加额外属性,也可以在页面放个隐藏字段,存原始的完整DateTime,在TimePicker的change事件里从这里取日期合并:
<!-- 隐藏字段存原始完整时间 --> <input type="hidden" id="originalStartTime" value="@Model.StartTime.ToString("yyyy-MM-ddTHH:mm:ss")" /> <!-- TimePicker控件 --> <input id="startTimePicker" /> <script> $("#startTimePicker").kendoTimePicker({ format: "HH:mm", value: new Date($("#originalStartTime").val()), change: function() { const original = new Date($("#originalStartTime").val()); const selected = this.value(); const merged = new Date(original.getFullYear(), original.getMonth(), original.getDate(), selected.getHours(), selected.getMinutes()); // 更新隐藏字段和ViewModel $("#originalStartTime").val(merged.toISOString()); viewModel.StartTime = merged; } }); </script>
总结下,两种思路都能解决问题:前端实时合并的方式用户体验更流畅,不会看到日期跳变;后台用原始属性的方式更稳妥,适合复杂表单场景。我个人更推荐第一种,毕竟用户操作的时候看不到异常变化会更舒服。
内容的提问来源于stack exchange,提问作者Tim Maes

