我目前在UTC中存储所有时间,以便当我开始将多个站点和服务器在线时更容易。
在模板中将date
和datetime
对象转换为字符串以及接受用户输入时,问题出现了。UTC下午6点对在太平洋标准时间的人来说意义不大。同样,要求用户以UTC输入时间也是自找麻烦。
我怎样才能以一种聪明的、不容易出错的方式正确地转换这些值?是否有一种方法可以从HTTP请求中确定用户所在的时区?我真的需要一种尽可能省力地确定用户所在时区的方法。
依赖客户端自我报告他们的时区的问题是,总是有一个机会(多大的机会是有争议的),你将真正得到的是一个UTC偏移。如果您获得UTC偏移量,那么您的逻辑在大多数时候都可以正常工作,但实际上只适用于客户端生成的精确时间戳。任何过去或未来的时间都可能有不同的UTC偏移量,如果没有适当的时区数据库,这是无法预测的。在夏令时边界附近,使用UTC偏移量可能会产生灾难性的错误结果。
除此之外,一些不识字的用户(例如奶奶)可能不知道如何设置当地系统的时区;或者在隧道会话或虚拟机上的用户可能有一个"本地"时区,而不是根据他们的实际偏好设置的。
根据您对客户端的了解(IP等)猜测客户端的政治时区可能是错误的,如果用户无法覆盖该猜测,则可能非常烦人。但对于匿名用户或新用户注册,我认为使用这种方法作为初始猜测没有错,只要你给用户一些方法来更改它,如果它是错误的。
我的建议是:
- 将Olson时区作为任何用户配置文件的一部分。时区可以按国家查询,这应该使用户选择他们的时区相对轻松。也给0.01%关心直接UTC选择的用户:-)
- 如果您使用基于ip的猜测填充用户配置文件中的默认值,那么如果您使用良好的查找服务,大多数情况下您都是正确的。但允许用户更改,如果它是错误的。
- 对于匿名用户,在任何显示或输入当地时间的页面上提供某种小部件,让他们选择自己的奥尔森时区,就像用户配置文件一样。将他们选择的值存储在cookie中。默认为UTC或上述猜测值。
在实现之前需要以本地化时间显示时间戳的基于web的应用程序时,我发现并非所有客户端都将UTC正确地转换为过去和未来日期的本地时间。我必须在服务器端执行所有转换。这可能需要一个接受本地时间和奥尔森时区并返回UTC时间的web服务。
我是这样做的。对于时区对象,您可能需要easy_install pytz。
import pytz
import time
import datetime
d = time.time()
print datetime.datetime.fromtimestamp(d, pytz.timezone('US/Eastern'))
print datetime.datetime.fromtimestamp(d, pytz.timezone('US/Central'))
print datetime.datetime.fromtimestamp(d, pytz.timezone('US/Mountain'))
print datetime.datetime.fromtimestamp(d, pytz.timezone('US/Pacific'))
这里的d变量将UTC时间存储为unix时间戳。
您无法可靠地从请求头中获取用户的时区。这就是为什么大多数网站要求用户在个人资料设置中设置时区。但是,您可以使用各种技巧来尝试获得。一个技巧是使用Google的IP-to-location api来找出用户来自哪里,然后尝试从地理位置猜测时区。这也不是100%可靠,但会让你更接近真相。
刚刚意识到这里已经至少问过一次:get user timezone
我不会做ip地理定位。它可能非常不准确,尤其是免费服务。只需向用户询问邮政编码或州,并将其存储在cookie中。
您可以使用javascript(它知道本地时间),在将数据发送到服务器之前将用户输入的时间更改为UTC。然后,以一种格式发送UTC,以便javascript可以将其从UTC转换为本地时间。
例如,要发送给服务器的UTC日期:
(new Date("November 11, 2011 23:13:42")).toUTCString()
将UTC转换为本地时间,用于呈现:
(new Date("October 17, 1986 15:29:13 UTC")).toLocaleString()