1

我有一个 mysql 数据库,用户可以向其中添加约会记录,并且我希望具有根据用户计算机的时区自动更改约会的 DateTime 值的功能。出于某种原因,我无法让它工作。

我已经尝试过现有的解决方案,但也许我遗漏了什么?随时将日期信息发送到数据库,我将时间转换为 UTC:

private void UpdateAppointment()
{
    using (ent = new ScheduleEntities())
    {
        var currentAppointment = ent.appointments.Attach(AppointmentIndex);

        currentAppointment.start = start_TimePicker.Value.ToUniversalTime();
        currentAppointment.end = end_TimePicker.Value.ToUniversalTime();

        ent.SaveChanges();
    }
}

然后在将记录添加到列表之前转换为本地时区:

private void ChangeTimeZone()
{
    Debug.WriteLine($"{TimeZone.CurrentTimeZone.StandardName}");

    foreach (var item in userAppointments)
    {
        Debug.WriteLine($"before: {item.start} - {item.end}");

        item.start = DateTime.SpecifyKind(item.start, DateTimeKind.Local);
        item.end = DateTime.SpecifyKind(item.start, DateTimeKind.Local);

        item.start = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(item.start, TimeZone.CurrentTimeZone.StandardName);
        item.end = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(item.end, TimeZone.CurrentTimeZone.StandardName);

        Debug.WriteLine($"after: {item.start} - {item.end}");
    }
}

private void PopulateAppointmentGrid()
{
    if (all_Radio.Checked)
    {
        ChangeTimeZone();
        var allQuery = ent.appointments.Where(ap => ap.userId == ActiveUser.userId);

        ForEachListItem(allQuery, ap => userAppointments.Add(ap));
    }
}
           

Debug.WriteLine 结果:

  • 时区(我手动设置从东部到中部,它会识别变化)
  • 之前:早上 8 点
  • 之后:上午 8 点

完整代码可以在这里找到:

https://github.com/AustinSB/SchedulingApplication

4

2 回答 2

1

对象从DateTimeMySQL 返回为DateTimeKind.Unspecified. 当您执行此代码时,它会强制将它们视为本地时间,但不会更改实际时间值:

item.start = DateTime.SpecifyKind(item.start, DateTimeKind.Local);
item.end = DateTime.SpecifyKind(item.start, DateTimeKind.Local);

这似乎不正确,因为您保存了 UTC 值:currentAppointment.start = start_TimePicker.Value.ToUniversalTime();

您的时区转换很可能什么都不做,因为它们已经是当地时间。

您可以尝试DateTime.SpecifyKind(item.start, DateTimeKind.Universal);,但如果您使用多个时区,您可能会遇到一组不同的错误。

DateTimeOffset考虑按照本文所述存储完整值: https ://mysqlconnector.net/troubleshooting/datetime-storage/ 。

于 2020-08-18T15:57:18.790 回答
0

一些东西:

  • 您正在使用正确地将本地时间转换为 UTC .ToUniversalTime()。这是有效的,因为当Kindis时Unspecified,它被视为本地。因此,您将 UTC 值保存到数据库中。

  • 您错误地断言从数据库中检索的值是当地时间。相反,使用 断言它们是 UTC SpecifyKind,然后使用 转换为本地时间ToLocalTime

    Unspecified此外,为了使此操作具有幂等性,我建议在进行任何转换之前检查kind。如果您多次调用您的方法,这将防止双重转换。

    if (item.start.Kind == DateTimeKind.Unspecified)
    {
        item.start = DateTime.SpecifyKind(item.start, DateTimeKind.Utc).ToLocalTime();
    }
    
    if (item.end.Kind == DateTimeKind.Unspecified)
    {
        item.end = DateTime.SpecifyKind(item.end, DateTimeKind.Utc).ToLocalTime();
    }
    
  • 由于您只在本地时间和 UTC 之间工作,因此您不需要获取系统的当前时区或时区标识符,也不需要涉及TimeZoneorTimeZoneInfo类的转换函数。(此建议仅适用,因为这是一个 Windows 窗体桌面应用程序。它不适用于 Web 应用程序,因为服务器的本地时区控制本地时间。)

  • 根本不要使用这个TimeZone类。曾经。原因很多,并在文档中说明。具体来说,在这种情况下,请注意TimeZone.CurrentTimeZone.StandardName返回一个本地化字符串,该字符串将根据区域设置而变化,并且并不总是与 ID 对齐 - 即使是英文。

于 2020-08-18T20:30:50.513 回答