C++语言环境是否有关联的时区?如果是的话,你如何访问它?

Lew*_*gle 15 c++ locale

我对此做了一些研究,我有非常有说服力的证据,答案是肯定的,答案是否定的.我不确定相信哪一方.

首先,我在cppreference.com上找到的文档和 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf似乎对此没有任何说明.我认为这是语言环境不支持时区的证据.

https://en.cppreference.com/w/cpp/locale/time_get/gethttps://en.cppreference.com/w/cpp/locale/time_put/put 都说:

%z以ISO 8601格式(例如-0430)写入UTC的偏移量,或者如果时区信息不可用则不写入字符%%Z写入时区名称或缩写,如果时区信息不可用则不写入字符(区域设置)依赖)

这似乎表明存在与locale()对象关联的时区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;
}
Run Code Online (Sandbox Code Playgroud)

在Linux(ubuntu)上,这给出了我期望的答案,+ 0000(好吧,我也不会对错误或空字符串感到惊讶).

但是在Windows(visual studio.net 2k17 - 15.8.7)上 - 这给出了:-0500

是的,正如你可能已经猜到的那样,我正在东部时区进行测试.但我仍然期望0,或空字符串(特别是对于locale :: classic()情况).

How*_*ant 10

直接回答你的问题

C++语言环境是否具有关联的时区?

没有.

它将来也不会.正如在问题中正确指出的那样,对于许多语言环境而言,由于语言环境所代表的地理区域可以具有多个时区,因此没有意义.

C标准确实在规范中说strftime:

%Z 由区域设置的时区名称或缩写替换,如果没有时区可确定,则替换为无字符. [tm_isdst]

但是C规范struct lconv没有提供这样的成员来存储该信息.规范确实允许实现添加此类成员,但实际上,实现不会使用C语言环境存储该信息.

C++语言环境根据C规范,POSIX规范以及一些添加来定义time_puttime_get定义自己,这些添加不包括时区名称或缩写.strftimestrptime

POSIX规范strftime比C规范更详细,并删除与"locale"的关联:

Z 如果不存在时区信息,则替换为时区名称或缩写,或者不替换为字节. [ tm_isdst]

POSIX规范struct lconv也比C规范更详细,但仍然没有为时区名称或缩写提供存储.

但是未来确实带来了更容易和有效地访问时区信息的希望,至少在C++中如此.

在C++ 20之前,C++具有以下知识:

  1. 单一时间标准:UTC,由Unix时间密切建模.

  2. 单个时区:由计算机的用户或管理员设置的"本地时区".UTC也可以用作本地时区.

如上所述,本地时区不是 C++(或C)语言环境数据的一部分.语言环境数据确实包含一些日历数据,例如:

  • 完整和缩写的工作日名称.
  • 完整和缩写的月份名称.
  • 用于显示日期和时间的本地常规格式(例如,年,月,日订购).

UTC offset(%z)和时区缩写(%Z)可能是可用的,但会作为本地时区数据的一部分而不是当前的区域设置数据存储,主要是因为之间没有良好的一对一映射时区和区域设置.

解释OP问题中提供的代码所发生的事情

在您的示例中:将 tm when{};所有成员归零tm,包括tm_isdst.当tm_isdst为零时,这意味着对于此特定,已知夏令时不起作用tm.

tm也允许有标准未指定的成员.一个流行的扩展是拥有一个tm_gmtoff以秒为单位保持UTC偏移的成员.如果您的Linux实现具有这样的成员,tm when{};则将其设置为0秒.如果您的Windows实现并没有这样的成员,UTC的本地时区的偏移将存储在别处.这解释了您所看到的差异,并且两种实现都是一致的.


有关如何访问时区的有用信息,因为C++语言环境不提供访问权限

在草案C++ 20规范中,存在一个名为的新类型std::chrono::time_zone.其中一个成员函数time_zone是:

template<class Duration> sys_info get_info(const sys_time<Duration>& st) const;
Run Code Online (Sandbox Code Playgroud)

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;
};
Run Code Online (Sandbox Code Playgroud)
  • 该范围[begin, end)告诉您此信息的有效时间(这些是UTC时间点).
  • offsettime_zone当前的UTC偏移量seconds.
  • 如果save != 0min,time_zone目前被认为是夏令时.
  • time_zone目前的缩写存储在abbrev.

此外,还有一个非会员功能:

const time_zone* current_zone();
Run Code Online (Sandbox Code Playgroud)

它返回指向当前本地时区的指针.总而言之,这是一个C++ 20程序,它打印出有关当前本地时区的有趣信息:

#include <chrono>
#include <iostream>

int
main()
{
    using namespace std::chrono;
    std::cout << current_zone()->get_info(system_clock::now()) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

这只是输出给我:

2018-03-11 07:00:00
2018-11-04 06:00:00
-04:00:00
01:00
EDT
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以使用Howard Hinnant的时区库,使用C++ 11,14或17来试验C++ 20的这一部分.该库将所有内容放在命名空间中date而不是std::chrono.

您还可以获取有关任何 IANA时区的信息,例如:

#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';
}
Run Code Online (Sandbox Code Playgroud)

只为我输出:

2018-10-06 16:00:00
2019-04-06 16:00:00
11:00:00
01:00
AEDT
Run Code Online (Sandbox Code Playgroud)

请注意,即使在C++ 20中,时区和语言环境也没有耦合.这样做是没有意义的.

  • 本地时区不是C和C++标准(C89/99/11和C++ 98/03/11/14/17)规定的C++(或C)语言环境数据的一部分.平台可能会将时区数据添加到区域设置作为扩展,但我不知道任何此类平台.我可以对libc ++/LLVM实现充满信心,因为我为Apple(一个基于BSD的系统)编写了所有`std :: locale`.我还编写了代码来检测Linux,macOS,iOS和Windows上当前设置的本地时区(`current_zone()`),并且没有任何代码检查当前设置的语言环境. (2认同)