3

问题

我想修改awful.widget.textclockawesome-wm 中的小部件以立即反映系统时区的变化。这个小部件和所有 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调用函数时。


用例

如果你很好奇,这个用例是在笔记本电脑上。我经常旅行并tzupdatesystemd timer. 我想自动更改我的时区。除了实际显示时间的小部件没有注意到系统时区的变化之外,这很好用。


到目前为止尝试过

  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()函数之后也是如此。

我克隆了luatzrepo 并复制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.

4

1 回答 1

1

The low level function behind os.date, localtime(3) "acts as if it called tzset(3)", tzset uses the environmental variable TZ to determine the timezone, and if that doesn't exist, read from /etc/localtime.

Environmental variables are mostly determined before your program starts, therefore, to get your timezone change to take place, you could find a way to set your TZ variable. A os.setenv is available via a few lua libraries, e.g. lua-ex

If that doesn't seem a reasonable course of action, you might be able to just ensure your script is started without TZ set at all; which will force tzset to read from /etc/localtime. Sadly, most of the time this file is cached, and you will not get updates; this depends on your system.

Alternatively, you could use a different library to obtain the time, instead of the os library. In luatz you can clear it's timezone cache with require "luatz.tzcache".clear_tz_cache(), you could call this function before fetching the time.

于 2014-08-09T20:30:53.337 回答