我对此进行了一些研究,并且我有令人信服的证据表明 答案为是,答案为否。我不确定该相信哪一方。
首先,我在cppreference.com上找到了文档,并且 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf对此一无所获。 我以此为依据,证明语言环境不支持时区。
但是https://en.cppreference.com/w/cpp/locale/time_get/get和https://en.cppreference.com/w/cpp/locale/time_put/put 都说:
%z以ISO 8601格式(例如-0430)写入UTC的偏移量,或者否 时区信息不可用时输入的字符%Z写入 时区名称或缩写,如果时区则没有字符 信息不可用(取决于语言环境)
似乎暗示存在与SOMETIMES相关的时区 语言环境()对象。
现在,如果您使用语言环境en_US.utf8(我的最爱之一;-)),那么实际上没有任何明智的选择 要关联的时区(美国包含至少4个或更多时区)。
是时候获得经验了。
我运行了代码:
#include <iostream>
#include <cstdlib>
#include <locale>
#include <sstream>
using namespace std;
int main ()
{
// locale l;
locale l = locale::classic ();
tm when{};
const time_put<char>& tmput = use_facet<time_put<char>> (l);
ostringstream oss;
oss.imbue (l);
static const string kTZOffsetPattern_{"%z"};
tmput.put (oss, oss, ' ', &when, kTZOffsetPattern_.c_str (), kTZOffsetPattern_.c_str () + kTZOffsetPattern_.length ());
cout << oss.str ();
return 0;
}
在Linux(ubuntu)上,这给出了我期望的答案,即+0000(好的,我也不会因错误或空字符串而感到惊讶)。
但是在Windows上(visual studio.net 2k17-15.8.7)-这给出了: -0500
是的,正如您可能已经猜到的,我正在东部时区进行测试。但是我仍然会期待 0或空字符串(尤其是locale :: classic()情况)。
答案 0 :(得分:10)
直接回答您的问题
C ++语言环境有关联的时区吗?
否。
将来也不会。正如问题中正确指出的那样,对于许多语言环境而言,这毫无意义,因为该语言环境所代表的地理区域可以具有多个时区。
C标准确实在规范strftime
中说过:
%Z
替换为语言环境的时区名称或缩写,如果没有则替换为任何字符 时区是可以确定的。[tm_isdst]
但是struct lconv
的C规范没有提供此类成员来存储该信息。该规范确实允许实现添加此类成员,但实际上,实现并不使用C语言环境存储该信息。
C ++语言环境方面time_put
和time_get
根据strftime
的C规范,strptime
的POSIX规范以及一些附加的内容来定义自己。包括时区名称或缩写。
strftime
的POSIX规范比C规范详细得多,并删除了与“ locale”的关联:
Z
替换为时区名称或缩写,如果不存在时区信息,则替换为无字节。[ tm_isdst]
struct lconv
的POSIX规范也比C规范详细得多,但仍不提供时区名称或缩写的存储。
但是未来的确为至少在C ++中更轻松有效地访问有关时区的信息带来了希望。
在C ++ 20之前,C ++具备以下知识:
单一时间标准:UTC,由Unix Time严格建模。
单个时区:计算机的用户或管理员设置的“本地时区”。 UTC也可以用作本地时区。
如上所述,本地时区不是C ++(或C)语言环境数据的一部分。语言环境数据确实包括一些日历数据,例如:
UTC偏移量(%z
)和时区缩写(%Z
) 可能可用,但将被存储为本地时区数据的一部分,而不是使用当前的语言环境数据,主要是因为在时区和语言环境之间没有良好的一对一映射。
OP提出的问题代码的解释
在您的示例中:tm when{};
将tm
的所有成员(包括tm_isdst
)清零。当tm_isdst
为零时,这意味着对于特定的tm
,夏令时无效。
tm
也被允许具有标准未指定的成员。一个流行的扩展名是拥有成员tm_gmtoff
,该成员拥有以秒为单位的UTC偏移量。如果您的Linux实现具有这样的成员,则tm when{};
会将其设置为0秒。如果您的Windows实现 not 没有这样的成员,则本地时区的UTC偏移量将存储在其他位置。这就解释了您所看到的差异,并且两种实现方式都是一致的。
由于C ++语言环境不提供访问权限,因此有关如何访问时区的有用信息
在C ++ 20规范草案中,存在一个名为std::chrono::time_zone
的新类型。 time_zone
的成员函数之一是:
template<class Duration> sys_info get_info(const sys_time<Duration>& st) const;
sys_time<Duration>
只是system_clock::time_point
,但精度为任何。因此,给time_zone
一个time_point
,然后返回一个sys_info
,其中包含有关 time_zone
在那个 time_point
:
struct sys_info
{
sys_seconds begin;
sys_seconds end;
seconds offset;
minutes save;
string abbrev;
};
[begin, end)
告诉您该信息在什么时候有效(这些时间是UTC时间点)。offset
是time_zone
中seconds
的当前UTC偏移量。save != 0min
,则time_zone
当前被认为是夏令时。time_zone
的当前缩写存储在abbrev
中。此外,还有一个非成员函数:
const time_zone* current_zone();
返回指向您当前本地时区的指针。综上所述,这是一个C ++ 20程序,该程序可以打印出有关当前本地时区的有趣信息:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
std::cout << current_zone()->get_info(system_clock::now()) << '\n';
}
这只是对我的输出:
2018-03-11 07:00:00
2018-11-04 06:00:00
-04:00:00
01:00
EDT
如果愿意,可以使用Howard Hinnant's timezone library,使用C ++ 11、14或17来试验C ++ 20的这一部分。该库将所有内容放置在命名空间date
中,而不是std::chrono
中。
您还可以获取有关任何 IANA time zone的信息,例如:
#include "date/tz.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << locate_zone("Australia/Sydney")->get_info(system_clock::now()) << '\n';
}
刚刚为我输出的内容:
2018-10-06 16:00:00
2019-04-06 16:00:00
11:00:00
01:00
AEDT
请注意,即使在C ++ 20中,时区和语言环境也是不耦合的。这样做没有意义。
答案 1 :(得分:3)
C ++语言环境是否具有关联的时区?
当前时区的所有方面均已实现定义。
C99中%Z
说明符的确切措辞(C ++将C库函数规范委托给C标准)
替换为语言环境的时区名称或缩写,如果无法确定时区,则不替换任何字符。
似乎有点模棱两可。一种解释确实是,语言环境可能会影响时区。另一个也不很恰当的措词是,语言环境会影响时区的名称或缩写。无论如何,似乎无法保证时区不受语言环境的影响,尽管我不希望这样。
您如何访问它?
据我所知,您不能使用标准库实用程序。无论如何都不是直接的,也没有办法对其进行修改。
打印当前时区的一种方法是使用%z
/ %Z
/ strftime
的{{1}}或put_time
格式说明符
还有一种方法可以将区域差异也获取为整数。 time_put
根据语言环境将std::mktime
结构解析为时间戳,而std::tm
根据UTC解析时间戳为std::gmtime
结构,因此,如果您从纪元开始,结合这两者,您将获得以秒为单位的当前语言环境时区和UTC的差异。
std::tm
答案 2 :(得分:0)
C标准(C ++标准所依赖)的相关段落说
%z被替换为ISO 8601格式“ −0430”中的UTC偏移量(意味着比格林尼治西部的UTC落后4小时30分钟),或者如果无法确定时区,则不替换任何字符。 [tm_isdst]
%Z替换为语言环境的时区名称或缩写,如果无法确定时区,则不替换任何字符。 [tm_isdst]
请注意,时区 name 被认为是与语言环境相关的,而时区 offset 则不受限制。
Cppreference需要修正其草率的措辞。