uliweb中timezone的处理
在很早以前的版本中,uliweb中就已经有了timezone的处理,在uliweb/utils/data.py中,已经定义了若干与日期、时间相关的api。那时我采用的是pytz来进行时区的处理。在default_settings.ini中GLOBAL/TIME_ZONE中设置了缺省的时区,缺省是None。同时uliorm中的日期、时间在自动生成时,也是使用date.py中的函数来生成的。启动uliweb时,会自动导入pytz,然后根据TIME_ZONE来设置时区。但是后来发现,pytz的tzinfo信息太大了,导入非常慢。于是就把这个自动初始化去掉了。因为pytz的时区数据太多,而且太复杂,比如夏令时的处理,的确使用起来比较麻烦。于是我就想只要简单的时区就够了,比如:UTC和GMT-12到GMT+12的时区,我想使用时区的人应该足够了解,他想要什么时区。
不过此事一直拖着,直到前两天花了些时间把这个事基本搞定了。首先参考了python手册中关于datetime模式中的tzinfo的示例(好象有部分是从pytz中来的),编写了UTC和GMT-12到GMT+12时区的类,并进行了初始化。然后又修改了date.py中的一些函数,使其更好用一些。然后又修改了uliorm中的DatetimeProperty, DateProperty, TimeProperty等属性类,同时调整了uliorm的validate的处理。
这样,在uliweb中使用时区可以有两种状态:1. 无时区状态。2.有时区状态。
在uliweb中的contrib中,新提供了一个timezone的app。一旦包含它,则自动根据settings.ini中的GLOBAL/TIME_ZONE中的设置初始化date.py中使用的缺省时区。这样,只要你的日期和时间函数都使用date.py中提供的方法,就可以自动处理时区。所谓无时区状态,就是TIME_ZONE为None。这样,其实都是服务器的时间,没有什么时区的概念,可能就是我们平常所使用的方式。而有时区状态,则TIME_ZONE不为空,比如设置成'UTC',则所有date.py中的函数缺省都使用'UTC'时区来生成时间。在uliorm中,日期和时间属性是可以通过添加auto_now和auto_now_add来自动在修改和添加时自动生成日期值,它就是使用了date.py中的now()函数。所以,一旦你设置了TIME_ZONE,则uliweb会自动按时区的方式进行处理。
对于时区的处理我们要考虑服务器和客户端有可能不一致的问题:
如果我们的服务器和用户的机器是在一个地区,这个问题最好办,可以不使用时区,直接使用本地时间。这样只要不设置TIME_ZONE或保持为None就好了。
但如果服务器和客户端可能不在一个地区,比如dotcloud的应用,那么就要考虑如何处理客户端的时区。这里我们可以统一服务器方的时区,通过设置TIME_ZONE。但是客户端的时区不好处理。比如:有用户的情况和无用户的情况。有用户的情况下,可以考虑让用户自行设置所在的时区。而无用户的情况下,如何获得时区有不同的做法。最简单的,就是默认客户时区。比如,uliweb中可以设置GLOBAL/LOCAL_TIME_ZONE,然后使用date.to_local()来将一个时间转为LOCAL_TIME_ZONE所指定的时区。另外在stackoverflow找到有类似的问题,比如这个,它的办法就是通过浏览器端执行一段javascript来比如与UTC的差异来获得时区差异,正好也是使用GMT +|-n的形式。其关键的js代码是:
<scripttype="text/javascript">
$(document).ready(function(){
if("<?php echo $timezone; ?>".length==0){
var visitortime =new Date();
var visitortimezone ="GMT "+-visitortime.getTimezoneOffset()/60;
$.ajax({
type:"GET",
url:"http://domain.com/timezone.php",
data:'time='+ visitortimezone,
success:function(){
location.reload();
}
});
}
});
</script>
这是php的例子,很容改为其它的程序形式。关键的地方就是:visitortime.getTimezoneOffset()/60 ,并且在得到时区后再自动刷新,然后将值保存到session中。
简单总结一下,通过设置GLOBAL/TIME_ZONE可以设置服务器端日期、时间的生成,比如uliorm的自动日期、时间的生成。其它地方的日期,通过使用date.py中的API。建议后台统一使用UTC日期,简单在uliweb中配置如下:
[GLOBAL]
TIME_ZONE = 'UTC'
同时要安装 'uliweb.contrib.timezone', 否则不起作用。
对于客户端的时区处理,有几种方法:
1. 先设置GLOBAL/LOCAL_TIME_ZONE的时区,然后使用date.to_local(datetime)来自动转为LOCAL_TIME_ZONE的时区,但这种也是相当于固定的时区,不能很灵活的自适应。
2. 在设计上,为每个用户添加一个时区选择的字段,让用户自行设置。这样在展示页面中,根据用户的时区值来转換时区显示。
3. 采用js在前端探测的办法,将前端的时区探测出来,并保存在session中,后续处理以此为客户端时区的处理。
同时还有一个要注意的,那就是用户上送的日期信息的处理。因为它也是不带时区的,所以要根据前面的方式默认为某个客户端时区再进行处理。