11.4 时区
从编程的角度来看,时区往往可怕而复杂。很多国家常有好几个时区,而且当一些(但不是全部)国家切换到夏令时需要改变边界。许多时区都有缩写名称,但它们又不是唯一的。例如,“EST”可以是美国、加拿大以及澳大利亚的“东部标准时间”。
在解析日期字符串时(使用strptime
),你可以指定一个时区;当你格式化它时(使用strftime
),可以再次改变它。在解析过程中,如果不指定时区(默认为“”),R会给日期以默认时区。这个值是Sys.timezone
返回的,它会从你的操作系统区域设置猜到该值。你可以使用Sys.getlocale
("LC_TIME"
)来查看操作系统的日期时间设定。
要避免这种时区的混乱,最简单的方法是随时记录,然后以UTC时区分析你的时间。如果你能做到这一点,恭喜!你很幸运。对于其他人,例如那些需要处理他人数据的人,最容易理解和方便的指定时区的方法是使用Olson形式,即“洲/市”或类似的方式:
strftime(now_ct, tz = "America/Los_Angeles")
## [1] "2013-07-17 14:47:01"
strftime(now_ct, tz = "Africa/Brazzaville")
## [1] "2013-07-17 22:47:01"
strftime(now_ct, tz = "Asia/Kolkata")
## [1] "2013-07-18 03:17:01"
strftime(now_ct, tz = "Australia/Adelaide")
## [1] "2013-07-18 07:17:01"
使用file.path(R.home("share"), "zoneinfo", "zone.tab")
能查找出R中所有可能的Olson时区列表(这是名为zone.tab的文件位于zoneinfo文件夹中,此文件夹就在你安装R的共享目录内)。本章后文将介绍lubridate
包,它将告诉你如何快速访问此文件。
另一个可靠的方法是给UTC手动添加一个偏移量,格式为"UTC"+n"
或 "UTC"-n"
。负的时间在UTC的东边,正的在西边。手动操作至少让你很清楚时间是如何被改变的,但同时你必须手动修正夏令时,因此这种方法须谨慎使用。最近版本的R会警告时区是未知的,但仍会正确执行此偏移操作:
strftime(now_ct, tz = "UTC-5")
## Warning: unknown timezone 'UTC-5'
## [1] "2013-07-18 02:47:01"
strftime(now_ct, tz = "GMT-5") #同样的结果
## Warning: unknown timezone 'GMT-5'
## [1] "2013-07-18 02:47:01"
strftime(now_ct, tz = "-5") # 如果操作系统支持,结果也是一样
## Warning: unknown timezone '-5'
## [1] "2013-07-18 02:47:01"
strftime(now_ct, tz = "UTC+2:30")
## Warning: unknown timezone 'UTC+2:30'
## [1] "2013-07-17 19:17:01"
指定时区的第三个方法是使用缩写,可以是三个字母或三个字母加一个数字再加三个字母的方式。这种方法不到最后不要使用,原因有三个:首先,缩写难以阅读,更容易出错;其次,正如前面提到的,它们不是唯一的,所以给出的时区可能不是你所要的;最后,不同的操作系统支持不同的缩写集。尤其对于Windows操作系统来说,它对时区缩写的处理比较别扭:
strftime(now_ct, tz = "EST") # 加拿大东部时间
## [1] "2013-07-17 16:47:01"
strftime(now_ct, tz = "PST8PDT") # 太平洋标准夏令时时间
## [1] "2013-07-17 14:47:01"
最后的关于时区的警告是:strftime
将忽略POSIXlt
类型的时区变更。最好在打印之前就显式把日期转换成POSIXct
类型:
strftime(now_ct, tz = "Asia/Tokyo")
## [1] "2013-07-18 06:47:01"
strftime(now_lt, tz = "Asia/Tokyo") # 时区没有变化!
## [1] "2013-07-17 22:47:01"
strftime(as.POSIXct(now_lt), tz = "Asia/Tokyo")
## [1] "2013-07-18 06:47:01"
还有一个最后警告(真的是最后一个啦!):如果你调用带有POSIXlt
参数的连接函数c
,它会把时区更改为当地时区。相反,如果把c
函数作用于POSIXct
参数上,将彻底去除其时区属性。(大多数其他的函数都将假定日期是本地时区的,但要小心!)