3

I know sudo tzsetup will prompt me to change time zone settings on FreeBSD.

➥ How can I see the current time zone settings, without making changes?

I know date shows me current time. For example:

Sun Dec 9 05:45:25 UTC 2018

…which I assumes mean the current default time zone is UTC.

But in this case:

Sat Dec 8 21:52:04 PST 2018

The PST is not a true time zone. Such 2-4 letter codes are neither standardized nor unique. True time zones are in the Continent/Region format such as Europe/Africa or Africa/Tunis (see Wikipedia).

How can I see the true time zone set as default?

This posting mentions using an environment variable TZ.

export TZ=America/Los_Angeles

But my FreeBSD 11.2 machine does not have such a variable set. So I suspect that is not the driving factor.

3
  • 1
    Dear Down-Voter, please leave a criticism along with your vote. Please indicate which rule for this site I have failed to meet. – Basil Bourque Dec 9 '18 at 6:00
  • Does it matter what the system time zone is? Why not just set TZ to the value that you want to use? – Kusalananda Dec 9 '18 at 8:31
  • 1
    @Kusalananda Yes, it matters, for troubleshooting and monitoring current configurations. – Basil Bourque Dec 9 '18 at 8:46
5

The TLDR answer is:

$ POSIXTZ=$(tail -n1 /etc/localtime)
$ echo $POSIXTZ
CET-1CEST,M3.5.0,M10.5.0/3

$ TZNAME=$(find /usr/share/zoneinfo | while read fname; do cmp -s /etc/localtime "$fname" && echo "$fname" | cut -c 21- ; done)
$ echo $TZNAME
Europe/Copenhagen

The current timezone is stored in the file /etc/localtime. As @Kusalananda remarks this can be a symbolic link. But as @JdeBP hints that on FreeBSD this file is normally copied from /usr/share/zoneinfo during setup.

These files originates from textual descriptions in contrib/tzdata

This information is then compiled into a binary format using zic and the format is specified in tzfile

I do not know of a built in utility which directly parses this file. But it should be easy to write in C with the documentation at hand. If we want to stick with what come out of the box we can look at it using hexdump.

hexdump -v -C /etc/localtime

Or if we just want to look at the magic marker:

$ hexdump -v -s 0 -n 5 -e '1/5 "%s\n"' /etc/localtime
TZif2

Or the fields:

tzh_ttisgmtcnt  The number  of UTC/local indicators stored in the file.
tzh_ttisstdcnt  The number  of standard/wall indicators stored in the file.
tzh_leapcnt     The number  of leap seconds for which data is stored in the file.
tzh_timecnt     The number  of ``transition times'' for which data is stored in the file.
tzh_typecnt     The number  of ``local time types'' for which data is stored in the file (must not be zero).
tzh_charcnt     The number  of characters of ``time zone abbreviation strings'' stored in the file.

Using:

hexdump -v -s 19 -n 4 -e '"tzh_ttisgmtcnt: " 1/4 "%9u\n"' /etc/localtime
hexdump -v -s 23 -n 4 -e '"tzh_ttisstdcnt: " 1/4 "%9u\n"' /etc/localtime
hexdump -v -s 27 -n 4 -e '"tzh_leapcnt:    " 1/4 "%9u\n"' /etc/localtime
hexdump -v -s 31 -n 4 -e '"tzh_timecnt:    " 1/4 "%9u\n"' /etc/localtime
hexdump -v -s 35 -n 4 -e '"tzh_typecnt:    " 1/4 "%9u\n"' /etc/localtime
hexdump -v -s 39 -n 4 -e '"tzh_charcnt:    " 1/4 "%9u\n"' /etc/localtime

Results in my case:

tzh_ttisgmtcnt:         0
tzh_ttisstdcnt:         6
tzh_leapcnt:            6
tzh_timecnt:            0
tzh_typecnt:          133
tzh_charcnt:            6

Then we do the following math to figure out where the first ttinfo starts:

43 + (tzh_timecnt * 4) + (tzh_timecnt * 1)
43 + (0 * 4) + (0 * 1) = 43

The wheels slowly falls of:

$ hexdump -v -s 43 -n 6 -e '"ttinfo:\n tt_gmtoff:      " 1/4 "%9u\n tt_isdst:       " 1/1 "%1d\n tt_abbrind:     " 1/1 "%1u\n"' /etc/localtime
ttinfo:
 tt_gmtoff:      2350816009
 tt_isdst:       96
 tt_abbrind:     155

With these numbers I am probably a little off. And this is truly a masochistic way of dealing with it. So I am stopped just short of finding the gold using tt_abbrind

But if we look at the bottom of the tzfile specification we find this little nugget:

After the second header and data comes a newline-enclosed, POSIX-TZ-environment- variable-style string for use in handling instants after the last transi- tion time stored in the file (with nothing between the newlines if there is no POSIX representation for such instants).

So it is as easy as:

$ tail -n1 /etc/localtime
CET-1CEST,M3.5.0,M10.5.0/

When you look closer you will notice that /etc/localtime does not contain any Continent/Region setting! But as the file is copied from /usr/share/zoneinfo you can compare them and find the probable file. I have not dived deep enough to confirm if /usr/share/zoneinfo might contain duplicates. But for me - this works nicely:

$ find /usr/share/zoneinfo | while read fname; do cmp -s /etc/localtime "$fname" && echo "$fname" | cut -c 21- ; done
Europe/Copenhagen

We iterate through all files in /usr/share/zoneinfo and compare each of them with /etc/localtime. cmp using the -s parameter will not display anything and only exit using a value. If the value is zero we will print the name. When printing the name we use cut to remove the first 21 characters to get Continent/Region

1
  • Unfortunately, echo $POSIXTZ and echo $TZNAME on my FreeBSD 12 system both return an empty line. – Basil Bourque Jul 21 '19 at 18:57
2

If the timezone has been set by tzsetup then the current timezone name is saved in /var/db/zoneinfo:

$ sudo tzsetup Europe/Berlin                                                                                                                                                                                  
$ cat /var/db/zoneinfo                                                                                                                                                        
Europe/Berlin

This allows to reinstall the timezone file /etc/localtime:

$ sudo rm /etc/localtime                                                                                                                                                      
$ sudo tzsetup -r                                                                                                                                                             
$ ls -l /etc/localtime                                                                                                                                                        
-r--r--r--  1 root  wheel  2309 Feb 15 10:59 /etc/localtime

If the timezone file has been copied manually instead using tzsetup then you have to find the name of the corresponding source file, as explained by Claus Andersen:

$ cd /usr/share/zoneinfo && find . -type f -exec cmp -s /etc/localtime '{}' \; -print | sed 's,^\./,,'                                                                        
Europe/Berlin

I have tested this with FreeBSD versions 11.3 and 12.1.

1

The current default timezone in used on FreeBSD, as well as on OpenBSD and NetBSD, will be evident from inspecting the /etc/localtime symbolic link. It will point to a time zone definition file under /usr/share/zoneinfo.

For example:

$ ls -l /etc/localtime
lrwxr-xr-x  1 root  wheel  36 Aug 11 13:51 /etc/localtime -> /usr/share/zoneinfo/Europe/Stockholm
2
  • 2
    This is not wholly reliable. /etc/localtime can be a regular file on FreeBSD, a copy of one of the zoneinfo files rather than a symbolic link to it; and in fact that is the default behaviour of tzsetup in the initial absence of that file. – JdeBP Dec 9 '18 at 14:15
  • I see only the part before the ->. So this does not indicate the default time zone to me. – Basil Bourque Jul 21 '19 at 18:55
1

The simple cross platform solution is to use date!

$ date +"%Z"
CET
$ date +"%z"
+0100

In your case you probably will get PST again - but I think this answer is important as well for those who can accept that. This take into account if TZ is set in the environment. And in practical use - the offset is often more usable than the Continent/Region.

2
  • 1
    As I explained, pseudo-zones like PST are not real time zones, not standardized, and many are not even unique! (CST, IST, etc.) And a true time zone is always preferable to a mere offset. A time zone is needed for proper date math, adding or subtracting some span of time while accounting for anomalies such as Daylight Saving Time (DST). So this Answer does not really address the specifics of the Question. – Basil Bourque Dec 10 '18 at 17:40
  • "for those who can accept that". But thank you for the lecture on time zones. That was really... helpful.... – Claus Andersen Dec 10 '18 at 17:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.