MinGW MSYS,MSVCRT和TZ环境变量

时间:2012-10-07 02:38:50

标签: timezone mingw msvcrt msys

简而言之,如何让MSVCRT和MinGW MSYS共享TZ环境变量而不会发生冲突?或者,如何使两个支持时区没有冲突?

更多信息

为了让MSYS的日期命令显示正确的本地时间,并且因为MSYS本身使用自己的C运行时而不是MSVCRT,我设置了TZ环境变量according to GNU C library documentation

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

不幸的是,this conflicts with Microsoft C runtime specs,它决定了DST名称部分:

  

如果夏令时在本地区永远不会生效,请设置TZ而不使用dzn的值。 C运行时库假定美国实施夏令时(DST)计算的规则

因此,在TZ变量中简单存在DST名称将导致依赖_tzset的程序在美国境外发生故障。这是我的Bazaar DVCS的情况,我迟到了一小时的提交时间,因为MSVCRT假设我已经根据TZ设置进入了DST期间。如果我将TZ留空,M​​SYS日期显示UTC时间,但MSVCRT(和Bazaar)工作正常。如果我如上设置TZ,那么MSVCRT会增加一小时的提交时间,但MSYS日期会显示本地时间。

Bazaar受到影响,因为它使用的是Python,后者又在Windows下使用MSVCRT。即使我可以从DST名称中删除所有内容,这将破坏MSYS中的日期命令。我也尝试了几种TZ值。 MSYS似乎缺少比上面GNU参考中描述的更多的时区支持。另外,我想避免仅在调用Bazaar时设置TZ,或者仅在调用date命令时设置TZ,而是更通用的解决方案。

替代格式和zoneinfo数据库

TZ有另一种格式,上面的GNU文档中有第三种格式,但MSYS似乎不支持,如上所述:

  

但POSIX.1标准仅指定前两种格式的详细信息,

似乎第三种格式只是IANA的时区数据库which describes a different format for TZ,MSYS似乎也不支持它,如上所述:

  

要在扩展POSIX实现上使用数据库,请将TZ环境变量设置为该位置的全名,例如TZ="America/New_York"

Desipe上面我试图手动将IANA的zoneinfo安装到MSYS上但没有成功。我不确定这些语句是否正确,MSYS甚至无法识别它们的格式,或者我是否无法正确安装zoneinfo数据文件。我找不到编译版本也不能自己编译,所以我只是尝试了Ubuntu的tzdata包。

但是,对我来说奇怪的是,上面的GNU C库文档已经提供了一个时区数据库(听起来像zoneinfo)。但是如上所述我在MSYS的任何地方都找不到任何类型的时区数据库,我也找不到任何与时区相关的mingw-get包。我想知道开发人员是否只是从发布中删除它。这就是文档所说的内容:

  

GNU C Library附带了一个大型时区信息数据库,供大多数地区使用,由志愿者社区维护并置于公共领域。

总而言之,如果我可以在MSYS中制作zoneinfo或类似的替代工作,那么我可以放弃目前设置TZ的方法,如上所述。但是,我无法找到有关MSYS中时区支持的任何有用信息。

3 个答案:

答案 0 :(得分:1)

简单的解决方案是按预期设置windows环境变量,然后将MSYS的〜/ .profile文件中的变量更改为POSIX所期望的值。

答案 1 :(得分:1)

我已经发现MSYS应该在没有TZ的情况下自动检测时区。以下错误报告记录了该问题:MSYS can't handle timeozones in localized Windows

同时

到目前为止,我发现的最佳解决方案是这个错误没有得到修复:

  1. 创建一个以示例runcrt.sh命名的包装脚本,可从系统路径获取并包含:

    #!/bin/bash
    env -u TZ $(basename "$0").exe "$@"
    
  2. 为此脚本创建NTFS符号链接,每个MSVCRT程序一个,我打算在MSYS中运行,但没有exe扩展,在系统路径中的实际可执行文件之前。例如,ruby,python,bzr等。

  3. 出于性能原因,在Windows初始化时将TZ的缓存配置(动态生成的导出语句)缓存到/etc/profile.d/timezone.sh(实际上我们只需要每年更新一次TZ,这是DST期间的频率。改变,但无论如何)。

  4. 将BASH_ENV设置为/etc/profile.d/timezone.sh,因此不仅可以使用交互式bash会话,还可以识别shell脚本。

  5. 这种方式,无论是交互式还是从shell脚本,例如,对bzr commit的调用都会在代码库中获得正确的提交日期,因为该命令是在TZ未设置的情况下执行的。类似地,TZ设置为所有其他命令,例如date和ls,因此它们也打印正确的本地时间。我已经放弃了仅针对MSYS命令设置TZ的相反方法,并将其留空其他任何内容,因为取消设置操作比导出导出要快得多。

    MSYS2作为替代

    然而,MSYS2不受此错误的影响,并正确识别时区。事实上,它有适当的时区支持:

    $ 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)
    

答案 2 :(得分:0)

在您的环境中,在没有msys的情况下运行纯Windows时没有任何问题。当您不访问本机Windows应用程序(如Bazaar)时,运行纯msys时没有问题。这就是我从你的问题中所假设的。

为在msys下运行的每个Windows命令取消设置TZ的特殊脚本包装器似乎是合理的,我想这就是你所做的。我知道这不是你期望的答案,也不是你自己写的答案,但由于没有其他答案,我认为至少有一个应该在这里:)最不邪恶。

最后,我设想3级设置TZ

  1. Windows系统设置中设置的Microsoft值
  2. /etc/profilemsys.bat
  3. 中设置的Msys值
  4. Microsoft在Msys中运行Windows命令的包装器中的值,例如:
    #!/bin/bash {
    {1}}
    在文件export TZ=; /usr/bin/bazaar "$@"
  5. 我无法想象一个更通用的解决方案。 shell如何知道给定命令首选哪个版本的/usr/local/bin/bazaar变量?