Timezone discrepancies from a developer perspective

Hello,

I had the situation that the timezone in regional settings was different then the timezone configured in “-Duser.timezone”. My question is, how to deal with it from a developer perspective.

e.g. pythonscripting relies on JVM default timezone. That means that the regional settings are completely ignored. If a enduser is not aware of it, it results in unexpected behaviors. He configured “Europe/Berlin” in openhab, but for some reason the startup setting was ‘-Duser.timezone=Europe/London’ and he was thinking that pythonscripting has the wrong timezone.

I have now 2 options.

  1. Fix/overwrite the default timezone in my binding with the value of the regional setting. Maybe with a warning.
  2. Just print a warning to show that pythonscripting is running with the timezone of ‘user.timezone’ then the regional setting and explain the consequences.

I personally would prefer solution 2, because solution 1 would maybe fix most of the usecases, but still it just hides to root cause by fixing the symptom.

Next thing is that I have the feeling that my binding is the wrong place for it. It should be handled in I18nProviderImpl

What do you think? Anyone with openhab core dev background has an option?

In my binding I’m handling it now in this way

I know this problem from the openHABian OS perspective. There’s an already huge amount of
OS settings that affect timezone, and they’re all different depending on the OS a user chooses and what he already knows about timezone configuration possibilities and what (s)he is used to using.

In the end, the user is and will remain responsible to ensure that any eventual -Duser.timezone setting matches with what he configures as regional settings, simple as that.
If he doesn’t, it doesn’t make sense to attempt working around this in code, so: just don’t.
Would just lead to more unexpected and hard to interpret behavior.

but maybe it would make sense to show a warning.

This is how I’m doing it currently with the pythonscripting binding. The question is, if we should have this kind of warning in a more central place and not only in my binding.

btw. in my binding I have no additional workaround, I just show a warning about this issues to create awareness for the user

I don’t think 1 is viable because the problem lies outside the python add-on. And if the Java timezone and OS timezones don’t match that means the user is going to experience other unexpected problems beyond just the python add-on.

There are tons of threads on the forums with users running into this issue. It would be nice if we could come up with some universal solution but what ever it is should probably be done in core or openhab-distro.

Despite the number of threads that have come up though, I don’t think we have a good idea why some users run into this problem while others do not. But what I do know is that usually, Java picks up the timezone from the OS. But only when the -Duser.timezone isn’t supplied. But when and how the -Duser.timezone gets set is hidden from the end users. Does apt/yum set that? Does only openHABian set that? :person_shrugging: (though this is a question that could be answered).

Most frustrating of all is the one place where the timezone is presented to the end user in MainUI → Settings → Regional settings does not seem to have any impact on what timezone OH actually operates under at all. I’m not even really certain why that option is there.

This is a long way to say this is and has remained a problem since OH 2.0 and a fix for it would be fantastic! But I don’t think individual add-ons should attempt to fix it piecemeal. I don’t see any problem with logging a warning. Though implementing that warning in core would be even better.

The only problem with this approach is that the user is ill equipped to do this. The one place where the user can obviously see to change the timezone has no practical effect. “user.timezone” appears nowhere in the OH docs (or at least it doesn’t show up with a search). openHABian has a way to set the timezone from the start, but that doesn’t help apt/yum/manual et al. users. Docker users pass the localtime and timezone files into the container and omits the -Duser.timezone command line property, but sometimes we still need to set the -Duser-timezone command line argument through an environment variable.

I put my comment on this topic here. I simultaneously opened another thread, which I will delete.

So here is my comment:

We had a longer discussion here about the timezone settings that are in

  • Linux system
  • Java options
  • openHAB

While I was trying to use some java.time.ZonedDateTime functions or even normal Python datetime functions in the Python Scripting, we found out that the system everywhere had the correct timezone (Europe/Berlin) configured, but in the EXTRA_JAVA_OPTS in /etc/default/openhab there was -Duser.timezone=Europe/London. And Python scripting seemed to use this one by java.time.ZoneId.systemDefault().getId()). Therefore, in the script timezone was set incorrectly.
I then corrected it in the file, which did not directly help, but after some add-on installations and openHAB restarts back and forth the incorrect timezone was gone.
Then I removed two add-ons, installed the Python Scripting Add-on again and the incorrect timezone was back again, but now after a clean-cache it is gone.

It is worth to mention that in JS Scripting, there are no native Java time classes, and JS-Joda uses other means to get the system default, therefore it is plausible that it does not happen there.

As Holger is sure that this behavior has nothing to do with the Python Scripting Add-on itself, I open a separate discussion here with the questions:

  • How can the -Duser.timezone setting for Java be influenced during the setup or installation process?
  • Can it be harmonized / synchronized with the openHAB or system settings for timezone?
  • Is this setting stored in the cache?
  • Any more suggestions / explanations?

When there are timezone discrepancies they appear ouside of scripts too. For example log timstamps are off, cron triggers happen at the wrong time, etc.

But joda-js gets the time from GraalVM same as python does, I suspect.

In openHABian you can set the timezone in the openhabian.conf file read during that first boot. For Docker -Duser.timezone is not set at all. The instructions have you mount /etrc/localtime and /etc/timezone into the container so the container is configured to the same time as the host. But you can add Java extra opts like this as an environment variable.

For everyone else :person_shrugging: I don’t think you can. You have to do it manually after the fact.

That’s the big question. By default Java is supposed to get the timezone from the operating system. However, you can override that by supplying the -Duser.timezone extra opt. Sometimes it appears that getting the timezone from the operating system doesn’t work and the only way to get it right is to supply the -Duser.timezone extra opt. When and why that fails :person_shrugging:

I can’t see how that would be the case. There is no file in temp nor the cache that refer to the timezone. /etc/default/openhab isn’t part of the cache.

This problem has been around for many many years. I’ve personally looked into it more than once. If I had any good ideas I would have tried to fix it before now. But there isn’t enough information to figure out why Java fails to get the timezone in the first place and/or the installers fail to set the proper timezone in /etc/default/openhab in the first place.

I did and placed Europe/Berlin there, but nevertheless I later found -Duser.timezone=Europe/London in the EXTRA_JAVA_OPTS.

I don’t think this is true, in my system JS scripts had it right all the time, also in this new installation where I have Python Scripting for the first time and then subsequently discovered the discrepancy.

No, joda-js is getting it from org.openhab.core.i18n.TimeZoneProvider.

Here is the code part where Joda ZoneId is initialized.

So in most cases, js is not affected. At least when you use ZonedDateTime in js.

In python it is different. There we use the native datetime which relies on JVM ZoneId.systemDefault()

Means if JVM default datetime is wrong, native python is wrong too.

A workaround for me would to “force/set” the correct ZoneId.systemDefault() if I detect differences to the TimeZoneProvider in my binding. But I don’t like to hide/fix the symptom. This is why I print now a warning (in the unreleased beta) to give the user a hint that something is wrong on his setup.

But org.openhab.core.i18n.TimeZoneProvider is part of the JVM too.

If I supply -Duser.timezone all the times in all my JS Scripts change to that timezone. The system default zone changes to match that.

Well, would already a good step to find out WHERE to change if some conflicting timezones are found.
I did it in /etc/default/openhab, but I am not 100% whether it did it. I undeliberately managed to get the wrong timezone back at a certain point during my trials. But nothing reproducible.

yes, but the TimeZoneProvider is initialized first with the timezone of regional settings from openhab. Only if this setting does not exists, it is falling back to the ZoneId.systemDefault

this means if you provide a regional setting, the result of TimeZoneProvider.getTimeZone can be different then ZoneId.systemDefault

Here is the code of TimeZoneProvider.getTimeZone where you can see this logic.

I think we are mixing 2 tasks, for the same topic here.

  1. How to handle this situation from a developer perspective. Means should we just show a warning in TimeZoneProvider

  2. How can we help @schup011 to fix his misconfiguration/unconfigured timezone setting of -Duser.timezone

  1. Ideally this should be detected and reported in core. But I have no problems if individual add-ons log warnings and that certainly will be the most expedient way to get this information out for python users.
  2. Traditionally because there is so much complexity the recommended solution is:
    a. set the operating system timezone
    b. set the -Duser.timezone to the same thing
    c. set the regional settings in MainUI → Settings → Regional Settings to the same thing.

With all three pointing to the same timezone all the various timezone problems have gone away in the past.

  1. What can we do to prevent these problems in the future or solve them easier when they occur? :person_shrugging: But this is probably the solution we should aim for.
1 Like

just as an info. Here is the javascript code which should show the differences.

the following code depends on JVM ZoneId.systemDefault

const javaZDT = Java.type('java.time.ZonedDateTime');
console.log(javaZDT.now())

the follwoing code depends on JVM TimeZoneProvider.getTimeZone

const ZDT = time.ZonedDateTime;
console.log(ZDT.now())

I would recommend to print a warning in TimeZoneProvider if all 3 things are not equal. With maybe some hints where to look into, to fix it.

It is really weird. In my system, the wrong timezone comes back and I don’t know how to get that fixed.

(My System: fresh openHABian installation, no container, on RasPi4, 4GB, openHAB 5.0.0.M4 with Temurin21).

On Friday I reported that at a certain point of time the discrepancy has gone.

I did not do much since then, now I’m coming back and I have this one:

console.log("JS: java.time.ZonedDateTime: " + java.time.ZonedDateTime.now());
console.log("JS: time.ZonedDateTime: " + time.ZonedDateTime.now());

Showing this output:

2025-07-20 16:09:48.760 [INFO ] [tomation.script.file.anfangswerte.js] - JS: java.time.ZonedDateTime: 2025-07-20T14:09:48.757955948Z[GMT]

2025-07-20 16:09:48.764 [INFO ] [tomation.script.file.anfangswerte.js] - JS: time.ZonedDateTime: 2025-07-20T16:09:48.762+02:00[Europe/Berlin]

My -Duser.timezone setting is Europe/Berlin

Maybe if we understand where it comes back from in my system we can find important insights about the discrepancy in general. I just need help where to search for (wrong) settings. Don’t have a clue.

  • Timezone setting in WebUI is Europe/Berlin
  • openhabian ssh shell shows CEST (i.e. Central European Standard Time, correct timezone)
  • openhabian-config shows correct timezone
  • ps -alx | grep openhab | grep timezone shows -Duser.timezone=Europe/Berlin

So where is this GMT setting coming from?

What I tried now is to add a TZ setting to
/etc/systemd/system/openhab.service.d/override.conf:

Environment=TZ=Europe/Berlin

I then did

sudo systemctl daemon-reexec
sudo systemctl restart openhab

And timezone is fixed for now. Any other ideas?

can you check if tzdata is installed on your system? I’m not sure if java depends on it, but maybe.

and can you please show the whole line of you openhab process.

ps -alx | grep openhab

maybe the setting -Duser.timezone occurs twice.

tzdata is installed and timezone occurs only once and shows
-Duser.timezone=Europe/Berlin

Can you show the complete process line, to see all parameters.

Here you are:

openhabian@openhabian:~ $ ps -alx | grep openhab
4   104     565       1  20   0   7496  2860 -      Ss   ?          2:37 avahi-daemon: running [openhabian.local]
4   105  245150       1  20   0 5363992 1629456 -   Ssl  ?         89:19 /usr/bin/java -XX:-UsePerfData -Dopenhab.home=/usr/share/openhab -Dopenhab.conf=/etc/openhab -Dopenhab.runtime=/usr/share/openhab/runtime -Dopenhab.userdata=/var/lib/openhab -Dopenhab.logdir=/var/log/openhab -Dfelix.cm.dir=/var/lib/openhab/config -Djava.library.path=/var/lib/openhab/tmp/lib -Djdk.util.zip.disableZip64ExtraFieldValidation=true -Djetty.host=0.0.0.0 -Djetty.http.compliance=RFC2616 -Dorg.apache.cxf.osgi.http.transport.disable=true -Dorg.ops4j.pax.web.listening.addresses=0.0.0.0 -Dorg.osgi.service.http.port=8080 -Dorg.osgi.service.http.port.secure=8443 -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Xms192m -Xmx768m -XX:-TieredCompilation -XX:TieredStopAtLevel=1 -XX:+ExitOnOutOfMemoryError -Dxtext.qn.interning=true -Duser.timezone=Europe/Berlin --add-reads=java.xml=java.logging --add-exports=java.base/org.apache.karaf.specs.locator=java.xml,ALL-UNNAMED --patch-module java.base=/usr/share/openhab/runtime/lib/endorsed/org.apache.karaf.specs.locator-4.4.7.jar --patch-module java.xml=/usr/share/openhab/runtime/lib/endorsed/org.apache.karaf.specs.java.xml-4.4.7.jar --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.naming/javax.naming.spi=ALL-UNNAMED --add-opens java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.base/java.time=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED --add-exports=java.base/sun.net.www.protocol.file=ALL-UNNAMED --add-exports=java.base/sun.net.www.protocol.ftp=ALL-UNNAMED --add-exports=java.base/sun.net.www.protocol.http=ALL-UNNAMED --add-exports=java.base/sun.net.www.protocol.https=ALL-UNNAMED --add-exports=java.base/sun.net.www.protocol.jar=ALL-UNNAMED --add-exports=java.base/sun.net.www.content.text=ALL-UNNAMED --add-exports=jdk.xml.dom/org.w3c.dom.html=ALL-UNNAMED --add-exports=jdk.naming.rmi/com.sun.jndi.url.rmi=ALL-UNNAMED --add-exports=java.rmi/sun.rmi.registry=ALL-UNNAMED --add-exports=java.security.sasl/com.sun.security.sasl=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED -Dkaraf.instances=/var/lib/openhab/tmp/instances -Dkaraf.home=/usr/share/openhab/runtime -Dkaraf.base=/var/lib/openhab -Dkaraf.data=/var/lib/openhab -Dkaraf.etc=/var/lib/openhab/etc -Dkaraf.log=/var/log/openhab -Dkaraf.restart.jvm.supported=true -Djava.io.tmpdir=/var/lib/openhab/tmp -Djava.util.logging.config.file=/var/lib/openhab/etc/java.util.logging.properties -Dkaraf.startLocalConsole=false -Dkaraf.startRemoteShell=true -classpath /usr/share/openhab/runtime/lib/boot/org.apache.karaf.diagnostic.boot-4.4.7.jar:/usr/share/openhab/runtime/lib/boot/org.apache.karaf.jaas.boot-4.4.7.jar:/usr/share/openhab/runtime/lib/boot/org.apache.karaf.main-4.4.7.jar:/usr/share/openhab/runtime/lib/boot/org.apache.karaf.specs.activator-4.4.7.jar:/usr/share/openhab/runtime/lib/boot/osgi.core-8.0.0.jar:/usr/share/openhab/runtime/lib/jdk9plus/istack-commons-runtime-3.0.12.jar:/usr/share/openhab/runtime/lib/jdk9plus/jakarta.xml.bind-api-2.3.3.jar:/usr/share/openhab/runtime/lib/jdk9plus/javax.annotation-api-1.3.2.jar:/usr/share/openhab/runtime/lib/jdk9plus/jaxb-runtime-2.3.9.jar:/usr/share/openhab/runtime/lib/jdk9plus/org.apache.servicemix.specs.activation-api-1.2.1-1.2.1_3.jar:/usr/share/openhab/runtime/lib/jdk9plus/txw2-2.3.9.jar org.apache.karaf.main.Main
4  1001  245155       1  20   0 730024 72516 -      Ssl  ?          0:08 node /usr/local/lib/node_modules/frontail/bin/frontail --disable-usage-stats --ui-highlight --ui-highlight-preset /usr/local/lib/node_modules/frontail/preset/openhab_AEM.json --theme openhab_AEM --lines 2000 --number 200 /var/log/openhab/openhab.log /var/log/openhab/events.log
4  1001  245299  245155  20   0   6000  2204 -      S    ?          0:02 tail -n 200 -F /var/log/openhab/openhab.log /var/log/openhab/events.log
0   105  246008  245150  20   0 1026036 159464 -    Sl   ?          1:46 node /var/lib/openhab/tmp/node-script-7102872074348970765.js --host localhost --port 35797
4     0  275226     706  20   0  19596  9852 -      Ss   ?          0:00 sshd: openhabian [priv]
5  1000  275250  275226  20   0  19856  6420 -      S    ?          0:00 sshd: openhabian@pts/0
0  1000  275570  275251  20   0   6464  2144 pipe_r S+   pts/0      0:00 grep --color=auto openhab
openhabian@openhabian:~ $