Very strange timezone behavior in Bash prompt

I suspect this is more to do with Bash than with Nix, but I’ve noticed some very surprising timezone behavior when displaying the current timestamp in a Bash prompt. I’ve paired it down to a minimal reproducible example.

Given the following shell.nix,

(import <nixpkgs> { }).mkShell {
  shellHook = ''
    PS1='\t  > '
  '';
}

when I enter the nix-shell, my prompt shows the current time in UTC:

$ nix-shell
23:38:30  > true
23:38:33  > true
23:38:36  >

If I change shell.nix so that a shell function is invoked to render the prompt,

(import <nixpkgs> { }).mkShell {
  shellHook = ''
    noop() { : ; }
    PS1='\t $(noop) > '
  '';
}

it initially shows the current time in UTC, but subsequent renders show it in my local time zone:

$ nix-shell
23:38:42  > true
18:38:45  > true
18:38:47  >

What do you make of this?

1 Like

I’m not sure it’s the same thing, but this reminds me a little of a bash timezone caching bug I reported this summer (printf builtin retains timezone from un-set TZ environment variable ; IIRC has been fixed, but the fix isn’t released yet).

I wonder a little if it’s actually the subshell causing it to recalculate, rather than the function call.

2 Likes

Invoking a subshell or an external command seems to fix it. This sounds like the timezone caching bug to me.

2 Likes

Interesting. It does appear to be the subshell, rather than the function call. The following setup behaves the same as the one with the function call:

(import <nixpkgs> { }).mkShell {
  shellHook = ''
    PS1='\t $(:) > '
  '';
}
2 Likes

With the original

(import <nixpkgs> { }).mkShell {
  shellHook = ''
    PS1='\t  > '
  '';
}

running /bin/echo hi at the prompt will also fix the timezone (running it from within the shell hook oddly won’t). So it’s not just subshells. Or running echo $(:) at the prompt will do it too. It seems like it’s the spawning of a new process that fixes it, though again I don’t know why doing it from within the shell hook doesn’t work.

1 Like