请先epoch与24时区的关系 理解基本概念
日期时间字符串转换成epoch
date-parse函数可以将字符串转换成秒数,这个功能相当方便。
> (setq e (date-parse "20140720 06:29" "%Y%m%d %H:%M"))
1405837740
注意
1. 06:29也可以是6:29, 加不加0都可以, 这很方便。:)
2. date-parse 接受的时间字符串参数要小心时区
像本例中的没有指明时区的就会被默认为UTC时区
3. 获取到的秒数是epoch的值, 没有包含时区的偏移,也是UTC时间的秒数。必须明确,epoch只有一个时区,就是UTC。
将epoch转换成日期时间字符串
这时候需要使用date函数。把上面得到的epoch:1405837740再转回去看看
注意:
date函数接收的参数是UTC的epoch
但是返回的却是当前时区的日期时间字符串
> (date e)
"Sun Jul 20 14:29:00 2014"
这里14:29比06:29多个8个小时,就是因为我们处于GMT+8时区。结果是正确的,只不过转换成了不同的时区。
offset参数
date函数是先将秒数转换成本地时区的时间,然后再看有没有offset参数。offset参数可以帮助转换成其他时区。
由于GMT+8 比 UTC多8小时,所以转换到UTC需要减去8小时,因此offset参数如下
> (date 1405837740 (- (* 8 60)))
"Sun Jul 20 06:29:00 2014"
用在线站点做了对比, 结果正确.
http://www.epochconverter.com/
date-parse获得指定时区时间的epoch
前面说过时间日期字符串里也是可以表达时区的, 据说是%z或者 %Z来格式化,但是没找到具体的例子。
如果没有指定时区,date-parse会认为这个日期时间字符串表示的是UTC时区。但是如果实际上这个字符串表示的是中国时间,GMT+8呢?
比如:"Sun Jul 20 14:29:00 2014" 里面没有包含时区格式,但是我们知道这是北京时间。所以需要对转换后的epoch做额外处理。下面是处理步骤:
1. date-parse函数认为这是UTC日期时间字符串,转换成epoch,记为x
2. 实际上日期时间字符串表示的是GMT+8时区,如果转换成epoch,应该记为y, y会比x小8小时。
为什么y比x小?
解释:一个epoch对应24个时区的日期时间字符串,这是1:24的对应关系。反过来,来自24个时区的相同的值的日期时间字符串对应的是24个epoch,时间越早的时区,epoch值越小。
所以需要将x减去8小时。下面的函数提供了一个参数time-offset,内部会减去它。
;; @str-date the date time value of specific time zone
;; @time-offset the offset seconds
;; @return nil if str-date is wrong
(define (datetime-str-to-epoch str-date date-format time-offset)
(let (epoch-seconds 0)
(setq epoch-seconds (catch (date-parse str-date date-format)))
(if epoch-seconds
(- epoch-seconds time-offset)
nil
)
)
)
每次先当作UTC时间字符串转换成epoch秒数,然后减去offset对应的秒数,获得相同时间字符串的实际时区对应的epoch。
下面是一个例子,利用(date)转换回当前时区做验证。
> (datetime-str-to-epoch "20140720 7:29" "%Y%m%d %H:%M" (* 8 3600))
1405812540
> (date 1405812540)
"Sun Jul 20 07:29:00 2014"