Pergunta

In short, how to make both MSVCRT and MinGW MSYS share the TZ environment variable without conflicts? Or, how to make both support timezones without conflicts?

Further information

In order to have date command of MSYS displaying correct local time, and because MSYS itself uses its own C runtime instead of MSVCRT, I have set TZ environment variable according to GNU C library documentation:

export TZ="BRT+3BRST,M10.3.0/0,M2.3.0/0"

Unfortunately, this conflicts with Microsoft C runtime specs, which dictates for the DST name part:

If daylight saving time is never in effect in the locality, set TZ without a value for dzn. The C run-time library assumes the United States' rules for implementing the calculation of daylight saving time (DST)

Hence, the simple presence of a DST name in TZ variable will cause programs relying on _tzset to malfunction outside the USA. This is my case with Bazaar DVCS, where I have been getting wrong commit times, one hour late, because MSVCRT assumes I have already entered DST period based on TZ setting. If I leave TZ empty, MSYS date displays UTC time, but MSVCRT (and Bazaar) works just fine. If I set TZ as above, then MSVCRT adds one hour to commit times, but MSYS date displays local time.

Bazaar is affected because it uses Python which in turn uses MSVCRT under Windows. Even though I can remove everything from DST name on, that will break date command in MSYS. I have tried several values of TZ as well. MSYS seems to lack any further timezone support than what is described above in GNU reference. Also, I wanted to avoid having TZ not set only when invoking Bazaar, or have it set only when invoking date command, but rather a more general solution.

Alternative formats and zoneinfo database

There is an alternative format for TZ, third one in GNU documentation above, but it seems to not be supported by MSYS, as stated:

But the POSIX.1 standard only specifies the details of the first two formats,

It seems this third format is just IANA's Time Zone Database, which describes a different format for TZ which seems to not be supported by MSYS either, as stated:

To use the database on an extended POSIX implementation set the TZ environment variable to the location's full name, e.g., TZ="America/New_York".

Desipe the above I tried to install IANA's zoneinfo manually onto MSYS without success. I'm not sure if these statements are correct and their formats aren't even recognized by MSYS, or if I just have failed to install zoneinfo data files correctly. I couldn't find a compiled version neither could I compile myself, so I just tried out the tzdata package from Ubuntu.

Something odd to me, though, is that GNU C library documentation above stands it comes with a timezone database already (it sounds to me like zoneinfo). However as said I can't find any kind of timezone database installed anywhere in MSYS, neither I can find any mingw-get package related to timezones. I wonder if the developers simply removed it from the release. This is what the documentation says:

The GNU C Library comes with a large database of time zone information for most regions of the world, which is maintained by a community of volunteers and put in the public domain.

So in sum, if I could make zoneinfo or similar alternative work in MSYS, then I could abandon my current approach of setting TZ as above. I can't find, however, any good information about timezone support in MSYS.

Foi útil?

Solução 2

I have figured out MSYS should actually detect timezone automatically without TZ. The following bug report documents the problem: MSYS can't handle timeozones in localized Windows.

In the meanwhile

The best solution I have found so far while this bug doesn't get fixed was:

  1. Create a wrapper script named for example runcrt.sh, available from system path and containing:

    #!/bin/bash
    env -u TZ $(basename "$0").exe "$@"
    
  2. Create NTFS symlinks to this script, one for each MSVCRT program I intend to run in MSYS, but without the exe extension and before the actual executables in system path. For example, ruby, python, bzr etc.

  3. For performance reasons, cache configuration of TZ (the export statement generated dynamically) into /etc/profile.d/timezone.sh on Windows initialization (actually we just need to update TZ once a year, which is how often DST period may ever change, but whatever).

  4. Set BASH_ENV to /etc/profile.d/timezone.sh, so not just interactive bash sessions but also shell scripts can be timezone aware.

This way, either interactively or from a shell script, calls to bzr commit, for instance, will get the right commit date into the code repository, because that command is being executed with TZ unset. Similarly, TZ is set for all the other commands such as date and ls, so they print the correct local time as well. I have dropped the opposite approach of setting TZ only for MSYS commands and leaving it blank for anything else because the unset operation is much faster than sourcing the export.

MSYS2 as alternative

MSYS2, however, is not affected by this bug and recognizes the timezone correctly. In fact, it has proper timezone support:

$ tzset
America/Sao_Paulo

$ date +"%T, timezone %Z (%z)"
10:18:12, timezone BRT (-0300)

$ TZ=America/Los_Angeles date +"%T, timezone %Z (%z)"
06:18:14, timezone PDT (-0700)

Outras dicas

The simple solution is to set your windows environment variable as you expect then change the variable in your ~/.profile file for MSYS to what POSIX expects.

In your environment you don't have any problems running pure Windows, without msys. And you have no problems running pure msys, when you don't access native Windows apps, like Bazaar. That's what I assume from your question.

Special script wrappers unsetting TZ for every windows command run under msys seems to be reasonable and I guess that's what you do. I know this is not the answer you expected or the one you could write yourself, but since there are no other answers, I thought at least one should be here :) The least evil.

Finally I imagine 3 levels of setting TZ:

  1. A value for Microsoft set in Windows system settings
  2. A value for Msys set in /etc/profile or msys.bat
  3. A value for Microsoft again in wrappers to run Windows commands within Msys, like:
    #!/bin/bash
    export TZ=; /usr/bin/bazaar "$@"
    in the file /usr/local/bin/bazaar

I can't imagine a more general solution. How can a shell know which version of TZ variable is preferred for the given command?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top