【问题标题】:How to update time in lua to reflect system timezone change during execution?如何更新 lua 中的时间以反映执行期间的系统时区变化?
【发布时间】:2014-08-08 20:55:27
【问题描述】:

问题

我想修改 awesome-wm 中的 awful.widget.textclock 小部件,以立即反映系统时区的变化。这个小部件和所有 awesome-wm 配置都是用 lua 编写的。

目前,如果系统时区发生更改,小部件将继续根据运行时设置的时区显示时间。小部件使用os.time 函数检索时间,但这与系统时间不匹配。


如下提供的解决方案

lua 脚本:

local tz=require"luatz";

require "luatz.tzcache".clear_tz_cache()
print("Before Changes (America/Los_Angeles)")
print(os.date("!%H:%M",tz.time_in()))

os.execute("timedatectl set-timezone America/Chicago")

require "luatz.tzcache".clear_tz_cache()
print("America/Chicago")
print(os.date("!%H:%M",tz.time_in()))

os.execute("timedatectl set-timezone America/New_York")
require "luatz.tzcache".clear_tz_cache()

print("America/New_York")
print(os.date("!%H:%M",tz.time_in()))

输出:

Before Changes (America/Los_Angeles)
15:33
America/Chicago
17:33
America/New_York
18:33

解决方法

这可以通过重新启动出色的窗口管理器来解决,这会导致小部件再次获得正确的时区。当然,如果时区发生变化,这需要再次重新启动窗口管理器。

期望的效果是在时区发生变化时从系统更新时区,无论是定期还是每次调用 os.time 函数时。


用例

如果您好奇,可以使用笔记本电脑。我经常旅行并在systemd timer 上运行tzupdate。我想自动更改我的时区。这很好用,只是实际显示时间的小部件不会注意到系统时区的变化。


到目前为止尝试过

  1. 取消设置“$TZ”环境变量。但是 Arch Linux 从一开始就没有设置这个变量,所以我不确定 lua 是如何确定正确的时区的。
  2. 使用luatz 库,特别是tzcache.clear_tz_cache() 函数。这似乎没有效果。
  3. 使用os.time()以外的函数检索系统时间:luatz.time()luatz.gettime.gettime()。这些函数的检索时间与其他函数相同。
  4. 使用luatz.time_in() 函数,但这会返回将时区偏移量两次应用于UTC 时间的时间。 luatz.time() 返回正确的本地时间,但应该返回 UTC 时间。

更新luatz

我尝试按照建议使用 luatz 库,但它似乎没有重新检查系统时区,即使在调用 tzcache.clear_tz_cache() 函数之后也是如此。

我克隆了luatz 存储库并将luatz 复制到系统模块目录。该脚本似乎可以正确加载,但并没有改变忽略系统时区更改的效果。据我所知,这与os.time() 函数没有什么不同。

luatz 测试脚本:

local luatz = require "luatz"
local tzcache = require "luatz.tzcache"
local gettime = require "luatz.gettime"

print ("\nBefore Change - System TZ is ")
os.execute("timedatectl | grep 'Time zone' | awk '{ print $3 }'")
print("\nos.time(): "..os.date("%H:%M", os.time()))
print("luatz.time(): "..os.date("%H:%M", luatz.time()))
print("gettime..gettime(): "..os.date("%H:%M", gettime.gettime()))

print("\nTime zone changed to America/New_York")
os.execute("timedatectl set-timezone America/New_York")

tzcache.clear_tz_cache()

print ("\nAfter  Change - System TZ is ")
os.execute("timedatectl | grep 'Time zone' | awk '{ print $3 }'")
print ("\nos.time(): "..os.date("%H:%M", os.time()))
print ("luatz.time(): "..os.date("%H:%M", luatz.time()))
print("gettime.gettime(): "..os.date("%H:%M", gettime.gettime()))

输出:

Before Change - System TZ is 
America/Los_Angeles

os.time(): 11:54
luatz.time(): 11:54
gettime..gettime(): 11:54

Time zone changed to America/New_York

After  Change - System TZ is 
America/New_York

os.time(): 11:54
luatz.time(): 11:54
gettime.gettime(): 11:54

luatz.time_in()

所以luatz.time_in() 函数会随着系统时区的变化而更新,我对此感到很兴奋!但是,time_in() 不显示正确的本地时间。它将时区偏移添加到正确的本地时间,导致时间落后几个小时。我尝试设置TZ 环境变量,但这没有效果。出于某种原因,luatz.time() 返回本地时间,luatz.time_in() 返回应用两次时区偏移的结果。

lua 脚本:

local tz=require"luatz";

require "luatz.tzcache".clear_tz_cache()
print("Before Changes (America/Los_Angeles)")
print(os.date("%H:%M",tz.time_in()))

os.execute("timedatectl set-timezone America/Chicago")

require "luatz.tzcache".clear_tz_cache()
print("America/Chicago")
print(os.date("%H:%M",tz.time_in()))

os.execute("timedatectl set-timezone America/New_York")
require "luatz.tzcache".clear_tz_cache()

print("America/New_York")
print(os.date("%H:%M",tz.time_in()))

输出:

Before Changes (America/Los_Angeles)
08:59
America/Chicago
10:59
America/New_York
11:59

实际系统当地时间:15:59

【问题讨论】:

    标签: lua timezone awesome-wm


    【解决方案1】:

    os.datelocaltime(3) 背后的低级函数“就像调用了 tzset(3)”、tzset 使用环境变量 TZ 来确定时区,如果不存在,请阅读来自/etc/localtime

    环境变量大多是在程序启动之前确定的,因此,为了让您的时区发生变化,您可以找到一种方法来设置您的 TZ 变量。 os.setenv 可以通过一些 lua 库获得,例如lua-ex

    如果这似乎不是一个合理的行动方案,您也许可以确保您的脚本在没有设置TZ 的情况下启动;这将强制tzset/etc/localtime 读取。可悲的是,大多数时候这个文件被缓存了,你不会得到更新;这取决于您的系统。

    或者,您可以使用不同的库来获取时间,而不是 os 库。在luatz你可以用require "luatz.tzcache".clear_tz_cache()清除它的时区缓存,你可以在获取时间之前调用这个函数。

    【讨论】:

    • 我正在运行没有设置 TZ 环境变量的 arch linux。 echo $TZ 在命令行中不返回任何内容,所以我不确定这是一个选项。我会调查luatz
    • luatz 函数即使在清除了tzcache 之后也会继续返回不正确的系统时间。
    • luatz.time() 是 UTC 时间。 luatz.time_in() 是当地时间。试试这个代码:codepad.org/3nt9p4Ub
    • 我试过luatz.time_in(),虽然它随着系统时区的变化而变化,但它没有报告正确的本地时间。有什么想法吗?
    • os.date 添加当前系统时区偏移量。 time_in 已经为你调整好了。在您的日期格式字符串前面加上 ! 以防止这种情况发生。 print(os.date("!%H:%M",tz.time_in()))
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 2020-01-23
    • 2011-01-16
    相关资源
    最近更新 更多