3

On Ubuntu 18.04, I have the following behavior of date:

$ date --version | head -n1
date (GNU coreutils) 8.28
$ date
Вт окт  8 13:18:18 MSK 2019
$ TZ=UTC date
Вт окт  8 10:18:23 UTC 2019

So far so good. But now I'm trying to do the same on Raspbian 9:

$ date --version | head -n1
date (GNU coreutils) 8.26
$ date
Tue Oct  8 13:18:50 MSK 2019
$ TZ=UTC date
Tue Oct  8 13:18:51 MSK 2019

What could be the reason for Raspbian version of date to ignore the TZ environment variable?

Ruslan
  • 3,290
  • 3
  • 28
  • 49

2 Answers2

5

I can think of two possible causes:

  1. the file /usr/share/zoneinfo/UTC is not present or is corrupted on your Raspbian 9, so glibc fails to implement the TZ variable setting and falls back to system default timezone,

  2. you may have a previously-configured TZ variable that has been marked as read-only, so your attempt to change it won't take effect.

Alexis Wilke
  • 2,697
  • 2
  • 19
  • 42
telcoM
  • 87,318
  • 3
  • 112
  • 232
  • Indeed, `dpkg -V tzdata` reveals that exactly this file was changed. And comparison of hashes shows that for some reason it had the same contents as `W-SU`. Doing `apt install --reinstall tzdata` and `dpkg-reconfigure tzdata` fixed the problem. – Ruslan Oct 08 '19 at 11:22
  • 1
    The system default timezone is determined by file `/etc/localtime`, which is, depending on distribution, either a symlink to `/usr/share/zoneinfo/some/zone` or a copy of the appropriate file from the zoneinfo directory. If it is a link, and someone attempts to copy a new file over it to change the system default timezone, the overwrite will actually happen to the file the link points to. So I guess your Raspbian originally had UTC linked as the default timezone, and an attempt was made to switch it by `cp /usr/share/zoneinfo/W-SU /etc/localtime`, but it ended up overwriting `...zoneinfo/UTC`. – telcoM Oct 08 '19 at 12:14
  • So you may wish to check that the system default timezone is still set correctly, and adjust it if necessary. If `/etc/localtime` is a symbolic link, you can either use e.g. `ln -sf /usr/share/zoneinfo/W-SU /etc/localtime` or just delete the old `/etc/localtime` first before copying/linking the desired timezone file in its place. – telcoM Oct 08 '19 at 12:17
  • You're spot on! After `dpkg-reconfigure tzdata` I now have a symlink to my desired default timezone, not a copy. – Ruslan Oct 08 '19 at 12:18
  • @Ruslan Raspberry is known for corrupting SD cards. Keep backups. – Rui F Ribeiro Oct 09 '19 at 10:45
  • @RuiFRibeiro I think in this case it was my mistake – exactly as telcoM explains in a comment, not FS corruption. But I do have a backup in any case. – Ruslan Oct 09 '19 at 10:56
2

The correct, standard and portable way to define via $TZ a time zone that is called UTC and is on (with 0 offset to) Universal Time all year round is with:

TZ=UTC0

That is self-contained and give the full specification for that timezone. That tells that the offset to UTC is 0 (all year round as there's no DST part specified) and the label (as reported by date +%Z for instance) is UTC.

The timezone specification as described by TZ can get more complicated as you can also embed the DST name and offset and the rules for when to change between summer and winter time. However, those rules are limited and in particular can't cover cases where the rules change change from one year to another (and in most countries, the rules have changed over time or use rules different from the first or last Sunday in some month).

That's why POSIX also specifies TZ=:something but with how something is handled left implementation defined to allow implementations to come up with a better way to define a timezone for real life zones.

On most systems, that's implemented using the ICANN's tz database (they also publish reference code to handle those).

So you'd use TZ=:Europe/London for instance for the mainland Britain timezone which covers timezone offsets and when the change for the current year and all past years in London.

In practice, Europe/London is interpreted as the path of a file relative to some zoneinfo directory (often /usr/share/zoneinfo).

In the tz database, there is also a Etc/UTC file (with Etc/Universal and Etc/Zulu links to it). Etc/GMT is defined the same way except the label is GMT all year round (with Etc/GMT-0, Etc/GMT+0, Etc/Greenwich as links).

So, you can do TZ=:Etc/UTC to get the same effect as TZ=UTC0 except that the system needs to open that Etc/UTC file to find out about the simplest of TZ rules: 0 offset to UTC all year round.

On many (most?) systems, there's a UTC -> Etc/UTC symlink, so you can also do TZ=:UTC.

TZ=UTC itself is not POSIX, but here in the absence of an offset being given, on most systems, it's interpreted as the same as TZ=:UTC (looks for the timezone definition in /path/to/zoneinfo/UTC. But if the tz database is not available, that won't work.

Also note that with date specifically, you can use the -u option to get UTC dates regardless of what $TZ contains. date -u is equivalent to TZ=UTC0 date.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501