Django 试图通过将日期内部存储在 UTC 中并将它们转换为客户端的时区进行显示来解决时区问题。这在理论上听起来不错,直到你意识到两件主要的事情:
- 许多时区可以并且确实存在于相同的 UTC 偏移量中。
- 由于没有时区 HTTP 标头,我们需要手动确定客户端的时区,这需要使用 JavaScript。但是,JavaScript 只能可靠地确定客户端的 UTC 偏移量,可能无法猜测正确的时区。
考虑到这两个问题,我认为一个简单的解决方案是完全忽略时区、DST 等,而是依赖客户端当前的 UTC 偏移量。在每次页面加载时,客户端上的 JavaScript 会使用客户端当前的 UTC 偏移量更新客户端的 cookie,而 Django 中的中间件将为每个请求加载该值。
问题是:Django 利用 get_current_timezone()
从上次调用时设置的值中检索timezone.activate()
数据。 timezone.activate()
将时区对象作为参数。
有没有办法使用只有 UTC 偏移量的timezone.activate()
?
您描述的解决方案是获取客户端的当前 UTC 偏移量并通过 cookie 或其他机制发送回服务器,这是一种常见的方法。 不幸的是,它是有缺陷的。 仅仅因为人们这样做并不能使它成为一个好主意。
问题是您从客户端收集的偏移量是针对特定时刻的。 但是,您可能不会在服务器上使用同一时刻。
例如,您可以在客户端上调用 new Date().getTimezoneOffset()
,这为您提供的值 480
,即 UTC 以西 480 分钟或UTC-08:00
(请注意登录反转(。 因此,您将 480 传递给服务器,以 UTC 格式从数据库加载日期,然后应用偏移量。 除了,也许您加载的日期是几个月前的,并且客户端对该日期的偏移量是UTC-07:00
。 因此,您应用了错误的偏移量,并生成了一个结果值,该值与应有的值相差一小时。
时区不能仅通过偏移量来标识。 时区标识符看起来像"America/Los_Angeles"
,而不仅仅是UTC-8
。 这是一个非常常见的错误。 在时区标签维基中的"时区!=偏移量"下阅读更多内容。
只有两种正确的方法可以处理这种情况:
-
使用像jsTimeZoneDetect或moment-timezone这样的库来猜测浏览器的时区,然后让用户选择他们的时区,默认为猜测的值。 然后,您可以在服务器端代码中使用选择或猜测的时区与 Django 或其他任何内容一起使用。
-
仅将UTC发送到客户端,使用JavaScript在浏览器中从UTC转换为本地时间。 (浏览器可以理解运行它的本地时区的行为,即使它无法识别它。 这里的问题是 - 由于此错误,较旧的浏览器可能会错误地转换较旧的日期。 但在大多数情况下,这仍然是一种合理的方法。