如何在Lua中更新时间以反映系统时区更改?

3

问题

我想要修改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

解决方案

可以通过重新启动 awesome 窗口管理器来解决此问题,这会使小部件再次获取正确的时区。当时区更改时,需要再次重启窗口管理器。

期望的效果是在系统更改时定期或每次调用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

1个回答

1

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

环境变量大多在程序启动之前确定,因此,要使您的时区更改生效,您可以找到一种设置TZ变量的方法。通过一些lua库,例如lua-ex,可以使用os.setenv

如果这似乎不是一个合理的行动,您可能只需确保在启动脚本时未设置TZ ,这将强制tzset/etc/localtime读取。不幸的是,大多数情况下,此文件被缓存,您将无法获得更新;这取决于您的系统。
或者,您可以使用其他库来获取时间,而不是os库。在luatz中,您可以使用require"luatz.tzcache".clear_tz_cache()清除它的时区缓存,您可以在提取时间之前调用这个函数。

我正在运行的是Arch Linux,它尚未设置TZ环境变量。在命令行中,“echo $TZ”返回空白,因此我不确定这是否是一个选项。我将研究一下“luatz”。 - JKav77
即使清除了“tzcache”,“luatz”函数仍然返回不正确的系统时间。 - JKav77
luatz.time() 是协调世界时。luatz.time_in() 是本地时间。尝试这段代码:http://codepad.org/3nt9p4Ub - daurnimator
os.date 添加了当前系统时区偏移量。time_in 已经为您进行了调整。在日期格式字符串前加上 ! 以防止这种情况发生。print(os.date("!%H:%M",tz.time_in())) - daurnimator
顺便提一下,你可以通过DBus订阅通知来代替轮询以检查时区是否更改:http://www.freedesktop.org/wiki/Software/systemd/timedated/ - daurnimator
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接