提升日期时间分析字符串

Boost Date Time Parsing string

本文关键字:字符串 时间 日期      更新时间:2023-10-16

我看过很多例子似乎解决了这个简单的情况。 我要解析的字符串是:

"2012-06-01 16:45:34 EDT"

我试图用下面的local_time_input_facet创建一个: "%Y-%m-%d %H:%M:%S %Z"

始终不设置 local_date_time 对象的区域指针。 阅读文档令人困惑:

%Z *! 完整时区名称(仅限输出)。将time_facet与 ptime 一起使用时,将忽略此标志。

"EDT"//东部夏令时间

以前有人这样做过吗?

更新:

我已经更新了代码以更好地说明问题:

using namespace std;
using namespace boost::local_time;
int main()
{
    stringstream ss;
    // Set up the input datetime format.
    local_time_input_facet *input_facet 
    = new local_time_input_facet("%Y-%m-%d %H:%M:%S %ZP");
    ss.imbue(std::locale(ss.getloc(), input_facet));
    local_date_time ldt(not_a_date_time),ldt1(not_a_date_time);
    // Read a time into ldt
    ss.str("2012-06-01 17:45:34 EDT");
    ss >> ldt;
    ss.str("2012-06-01 17:45:34 CDT");
        ss >> ldt1;
        std::cerr << (ldt - ldt1).total_seconds() << std::endl;
    // Write the time to stdout.
    cout << "Full Time:t"   << ldt.to_string() << endl;
    cout << "Local time:t"  << ldt.local_time() << endl;
    cout << "Time zone:t"   << ldt.zone_as_posix_string() << endl;
    cout << "Zone abbrev:t" << ldt.zone_abbrev() << endl;
    cout << "Zone offset:t" << ldt.zone_abbrev(true) << endl;
    cout << "Full Time:t"   << ldt1.to_string() << endl;
    cout << "Local time:t"  << ldt1.local_time() << endl;
    cout << "Time zone:t"   << ldt1.zone_as_posix_string() << endl;
    cout << "Zone abbrev:t" << ldt1.zone_abbrev() << endl;
    cout << "Zone offset:t" << ldt1.zone_abbrev(true) << endl;
    return 0;
}

输出:

0
Full Time:  2012-Jun-01 17:45:34 EDT
Local time: 2012-Jun-01 17:45:34
Time zone:  EDT+00
Zone abbrev:    EDT
Zone offset:    +0000
Full Time:  2012-Jun-01 17:45:34 CDT
Local time: 2012-Jun-01 17:45:34
Time zone:  CDT+00
Zone abbrev:    CDT
Zone offset:    +0000

The Bug

根据boost的文档,这里: http://www.boost.org/doc/libs/1_57_0/doc/html/date_time/date_time_io.html#date_time.format_flags

%Z是:

完整时区名称(仅限输出)。

它还对%ZP说:

Posix 时区字符串(可用于输入和输出)。

所以你需要把%Z改成%ZP.现在,您的时间戳将解析。但是,您会注意到不会设置区域偏移量。

波西斯时区字符串

对于 Posix 时区字符串,您至少需要指定区域缩写和与 UTC 的偏移量,例如 EST-5 .

完整的 Posix 时区字符串的格式为:

"std offset dst [offset],start[/time],end[/time]"

根据 http://www.boost.org/doc/libs/1_57_0/doc/html/date_time/local_time.html#date_time.local_time.posix_time_zone 的说法,没有空格

以下是 EST 和 PST 的完整 Posix 时区字符串的一些示例:

EST-5EDT,M3.2.0,M11.1.0
PST-8PDT,M4.1.0,M10.1.0

其中包含有关夏令时何时生效的信息。

但是,在您的情况下,您也许可以逃脱EDT-4,具体取决于您如何处理它。

应该注意的是,尽管 Posix 时区很简单,但它们的局限性在于它们不考虑时区规则的历史变化。我认为最好首先避免使用时区。

如果我无法控制输入格式怎么办?

正如OP在注释中指出的那样,偏移量未在他的输入时间戳中列出。一种解决方案是从输入时间戳的末尾读取区域缩写(例如 "EDT" ),并根据已知区域缩写的地图进行检查:

std::map<std::string, std::string> zone_map;
zone_map["EST"] = "EST-5EDT,M4.1.0,M10.5.0";  // Eastern Standard Time
zone_map["EDT"] = zone_map["EST"];            // Eastern Daylight Time
zone_map["PST"] = "PST-8PDT,M4.1.0,M10.1.0";  // Pacific Standard Time
zone_map["PDT"] = zone_map["PST"];            // Pacific Daylight Time
// ...

(请注意,上述 DST 区域应与标准时区相同。

您也可以只存储简单的 UTC 偏移量:

zone_map["EST"] = "EST-5";  // Eastern Standard Time
zone_map["EDT"] = "EDT-4";  // Eastern Daylight Time
// ...

工作示例

下面是使用内置时区数据库的示例:

#include <map>
#include <string>
#include <sstream>
#include <iostream>
#include <boost/date_time/local_time/local_time.hpp>
using namespace boost::local_time;
int main()
{
    // A little database of time zones.
    std::map<std::string, std::string> zone_map;
    zone_map["EST"] = "EST-5EDT,M4.1.0,M10.5.0";  // Eastern Standard Time
    zone_map["EDT"] = zone_map["EST"];            // Eastern Daylight Time
    zone_map["PST"] = "PST-8PDT,M4.1.0,M10.1.0";  // Pacific Standard Time
    zone_map["PDT"] = zone_map["PST"];            // Pacific Daylight Time
    // ...
    // This is our input timestamp.
    std::string timestamp = "2012-06-01 16:45:34 EDT";
    // Replace time zone abbrev with full Posix time zone.
    const size_t abbrev_pos = timestamp.find_last_of(' ') + 1;
    const std::string abbrev = timestamp.substr(abbrev_pos);
    timestamp.replace(abbrev_pos, std::string::npos, zone_map[abbrev]);
    std::cout << "Time stamp with full timezone: " << timestamp << std::endl;
    // Set up the input datetime format.
    local_time_input_facet *input_facet = new local_time_input_facet("%Y-%m-%d %H:%M:%S %ZP");
    std::stringstream ss;
    ss.imbue(std::locale(ss.getloc(), input_facet));
    // This is our output date time.
    local_date_time ldt(not_a_date_time);
    // Read the timestamp into ldt.
    ss.str(timestamp);
    ss >> ldt;
    // Write the time to stdout.
    std::cout << "Full Time:t"   << ldt.to_string() << std::endl
              << "Local time:t"  << ldt.local_time() << std::endl
              << "Time zone:t"   << ldt.zone_as_posix_string() << std::endl
              << "Zone abbrev:t" << ldt.zone_abbrev() << std::endl
              << "Zone offset:t" << ldt.zone_abbrev(true) << std::endl;
    return 0;
}

这输出:

Time stamp with full timezone: 2012-06-01 16:45:34 EST-5EDT,M4.1.0,M10.5.0
Full Time:      2012-Jun-01 16:45:34 EDT
Local time:     2012-Jun-01 16:45:34
Time zone:      EST-05EDT+01,M4.1.0/02:00,M10.5.0/02:00
Zone abbrev:    EDT
Zone offset:    -0400

虽然这里的解决方案可能并不理想,但这是我能看到的唯一方法。