How do I update the time in lua to reflect the system timezone change at runtime?

Problem

I want to change the widget awful.widget.textclock

in awesome-wm to reflect the change in the system timezone right away. This widget and all awesome-wm config are written in lua.

Currently, if the system time zone is changed, the widget continues to display the time according to the time zone set at runtime. The widget uses a function os.time

to get the time, but this does not match the system time.


Solution given below

lua script:

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()))

      

Output:

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

      


Bypass

This can be solved by restarting the awesome window manager which makes the widget get the correct timezone again. Naturally, if changing the time zone requires restarting the window manager.

The desired effect is to update the timezone from the system when it changes, either periodically or every time the function is called os.time

.


Use register

If you're interested, there is a precedent for this on a laptop. I often travel and run tzupdate

on systemd timer

. I would like to automate changing my timezone. This works great, except that the widget that actually displays the time doesn't notice the system timezone change.


Tried so far

  • Cancel the $ TZ environment variable. But Arch Linux never sets this variable in the first place, so I'm not sure how lua even determines the correct timezone.
  • Use a library luatz

    and in particular a function tzcache.clear_tz_cache()

    . It doesn't seem to have any effect.
  • Get the system time using functions other than os.time()

    : luatz.time()

    and luatz.gettime.gettime()

    . They retrieve the same time as other functions.
  • Use a function luatz.time_in()

    , but this returns the time when the timeline offset is applied twice to UTC time. luatz.time()

    returns the correct local time, but must return UTC time.

UPDATED luatz

I tried messing around with the library luatz

as recommended, but doesn't seem to recheck the system timezone even after the function call tzcache.clear_tz_cache()

.

I cloned the relay luatz

and copied luatz

to the system modules directory. The script seems to load correctly, but did not change the effect of ignoring the system timezone change. As far as I can tell, this does nothing but a function os.time()

.

luatz test script:

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()))

      

Output:

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()

This way the function is luatz.time_in()

updated as the system timezone changes, and I love it! However, it time_in()

does not display the correct local time. It adds the time zone offset to the correct local time, resulting in a few hours behind. I experimented with setting the environment variable TZ

, but it had no effect. luatz.time()

Returns local time for some reason , but luatz.time_in()

returns the result of double timezone offset.

lua script:

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()))

      

output:

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

      

Current local time systems: 15:59

.

+3


source to share


1 answer


The low-level function behind os.date

, localtime(3)

"acts like it's called tzset(3)

", tzset

uses an environment variable TZ

to determine the timezone, and if that doesn't exist, read on from /etc/localtime

.

Environment variables are mostly defined before you start your program, so to change your timezone, you can find a way to set your variable TZ

. A os.setenv

is available through several lua libraries eg. lua-ex



If that doesn't seem like a sane way, you can simply ensure that your script runs without TZ

; which will force tzset

reading from /etc/localtime

. Unfortunately, most of the time this file is cached and you will not receive updates; it depends on your system.

Alternatively, you can use a different library to get the time, not a library os

. In luatz

you can clear the timezone cache with require "luatz.tzcache".clear_tz_cache()

, you can call this function before getting the time.

+1


source







All Articles