There's code in tzcode (and, I suspect not coincidentally, glibc's localtime implementation as well) to not call the internal version of tzset on calls to localtime_r, but rather only on calls to localtime. The justification is that Posix says localtime_r doesn't need to update the global tzname variable. I don't have a copy of the Posix spec handy, so I can't check: does Posix also say that localtime_r doesn't need to check for and make use of a possibly-changed value of TZ? As implemented (both in tzcode and glibc), it doesn't. If a program calls localtime, then calls setenv to set a new value of TZ, then calls localtime again, it works as expected, but if it calls localtime_r, setenv, localtime_r, it doesn't. (The workaround, of course, is to call localtime_r, setenv, tzset, localtime_r.)