4

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

更多的信息

为了让 MSYS 的 date 命令显示正确的本地时间,并且因为 MSYS 本身使用自己的 C 运行时而不是 MSVCRT,我根据 GNU C 库文档设置了 TZ 环境变量:

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

不幸的是,这与 Microsoft C runtime specs 冲突,后者规定了 DST 名称部分:

如果夏令时在该地区从未生效,请设置 TZ 而不为 dzn 设置值。C 运行时库假定美国实施夏令时 (DST) 计算的规则

因此,在 TZ 变量中简单地存在 DST 名称将导致依赖于_tzset美国以外的程序出现故障。这是我在 Bazaar DVCS 的情况,我的提交时间错误,晚了一小时,因为 MSVCRT 假设我已经根据 TZ 设置进入 DST 期间。如果我将 TZ 留空,MSYS 日期会显示 UTC 时间,但 MSVCRT(和 Bazaar)工作得很好。如果我如上所述设置 TZ,则 MSVCRT 会增加一小时的提交时间,但 MSYS 日期显示本地时间。

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

替代格式和 zoneinfo 数据库

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

但是 POSIX.1 标准只规定了前两种格式的细节,

似乎这第三种格式只是 IANA 的时区数据库,它描述了一种不同的 TZ 格式, MSYS 似乎也不支持,如下所述:

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

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

不过,对我来说奇怪的是,上面的 GNU C 库文档已经带有一个时区数据库(在我看来,这听起来像 zoneinfo)。但是,如前所述,我在 MSYS 的任何地方都找不到安装任何类型的时区数据库,也找不到与时区相关的任何 mingw-get 包。我想知道开发人员是否只是将其从版本中删除。这就是文档所说的:

GNU C 库带有一个包含世界大部分地区时区信息的大型数据库,该数据库由志愿者社区维护并置于公共领域。

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

4

3 回答 3

1

简单的解决方案是按照您的预期设置您的 Windows 环境变量,然后将 MSYS 的 ~/.profile 文件中的变量更改为 POSIX 的预期。

于 2012-10-16T11:53:40.730 回答
1

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

与此同时

到目前为止,我发现的最佳解决方案是:

  1. 创建一个名为 example 的包装脚本runcrt.sh,可从系统路径获得并包含:

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

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

  4. 将 BASH_ENV 设置为/etc/profile.d/timezone.sh,因此不仅交互式 bash 会话而且 shell 脚本也可以感知时区。

这样,无论是交互方式还是从 shell 脚本,对 的调用bzr commit都会将正确的提交日期放入代码存储库,因为该命令是在未设置 TZ 的情况下执行的。同样,为所有其他命令(例如 date 和 ls)设置了 TZ,因此它们也打印正确的本地时间。我已经放弃了仅为 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)
于 2012-10-29T17:21:21.667 回答
0

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

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

最后我想象3个级别的设置TZ

  1. 在 Windows 系统设置中为 Microsoft 设置的值
  2. Msys 的值设置在/etc/profilemsys.bat
  3. Microsoft 再次在包装器中运行 Msys 中的 Windows 命令的值,例如:
    #!/bin/bash
    export TZ=; /usr/bin/bazaar "$@"
    在文件中/usr/local/bin/bazaar

我无法想象更通用的解决方案。shell 如何知道TZ给定命令首选哪个版本的变量?

于 2012-10-09T07:39:27.857 回答