从日期字符串获取日期,月份和年份值

时间:2020-08-31 19:51:52

标签: c++

我想从字符串中获取日期,月份和年份信息。

示例日期字符串:2020年7月30日,星期四00:51:08 -0700(PDT)

PDT此处是太平洋夏令时间。创建文件时,此字符串偏移量(-0700)可以根据系统时区进行更改。

我需要编写一个c ++程序来从该字符串中提取日期,月份和年份。

关于如何解决此问题的任何想法?

2 个答案:

答案 0 :(得分:2)

这是一个进化的故事。正确的答案很大程度上取决于您当前使用的工具集(它有多现代)。即使它完全是现代的,还是会有更好的工具。

哈比斯人

在C ++ 98中,我们可以直立。我们有工具可以扫描int个数组中的char个。 scanf是执行此操作的工具。此结果的类型不安全,但是我们可以扫描整数和字符串,然后将这些值重新解释为日期的组成部分:年,月和日。这可能看起来像这样:

#include <cstdio>
#include <cstring>
#include <iostream>

int
main()
{
    using namespace std;

    string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
    char const* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
                            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    char wd[4] = {};
    int d;
    char mon[4] = {};
    int y;
    sscanf(s.c_str(), "%s %d %s %d", wd, &d, mon, &y);
    int m;
    for (m = 0; m < 12; ++m)
        if (strcmp(months[m], mon) == 0)
            break;
    ++m;
    cout << y << '\n';
    cout << m << '\n';
    cout << d << '\n';
}

这将输出:

2020
7
30

注释:

  • " 00:51:08 -0700 (PDT)"从未被解析。 可以进行解析。但这还需要做很多工作。
  • 没有错误检查。这可能是一个有效日期,也可能不是。
  • 没有类型安全性。结果只是int,如果将它们混合在一起,那是运行时错误,而不是编译时错误。

尼安德特人

使用C ++ 98,还有一种流行的但是 非标准解决方案:strptime

#include <time.h>
#include <iostream>

int
main()
{
    using namespace std;

    string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
    tm tm;
    strptime(s.c_str(), "%a, %d %b %Y %T", &tm);
    cout << tm.tm_year + 1900 << '\n';
    cout << tm.tm_mon + 1 << '\n';
    cout << tm.tm_mday << '\n';
    cout << tm.tm_hour << '\n';
    cout << tm.tm_min << '\n';
    cout << tm.tm_sec << '\n';
}

strptime在POSIX标准中,但不在C或C ++标准中。 MS Visual Studio也支持它。因此,这是一个受欢迎的扩展。并且有充分的理由。它的级别更高,并将结果放入struct tm中:一种表示日期/时间的类型;类型安全性的开端。

输出:

2020
7
30
0
51
8

仍然存在一些问题:

  • " -0700 (PDT)"不会被解析。无法要求strptime执行此操作。
  • tm的不同字段上存在偏移量和不一致的偏移量。例如,月份从零开始,日期从一开始。但是至少它也知道如何解析时间,而且相对容易。
  • 有错误检查,但很容易忽略。如果发生不好的情况,strptime返回NULL

Cro-Magnon

随着C ++ 11到达strptime周围的实际C ++包装器,并由std::get_time正式由C ++标准认可:

#include <iomanip>
#include <iostream>
#include <sstream>

int
main()
{
    using namespace std;

    string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
    istringstream in{s};
    in.exceptions(ios::failbit);
    tm tm;
    in >> get_time(&tm, "%a, %d %b %Y %T");
    cout << tm.tm_year + 1900 << '\n';
    cout << tm.tm_mon + 1 << '\n';
    cout << tm.tm_mday << '\n';
    cout << tm.tm_hour << '\n';
    cout << tm.tm_min << '\n';
    cout << tm.tm_sec << '\n';
}

使用C ++包装器,您可以从流中进行解析,这使您可以在解析失败时引发异常。但是它仍然是一个简单的包装器,因此结果只是一个tm。这与以前的解决方案具有相同的怪异性。

输出与以前的解决方案相同:

2020
7
30
0
51
8

智人

尽管C ++ 11中引入了强类型std::chrono time_point / duration系统,但直到C ++ 20才将其与民用日历集成在一起,类似于get_time的功能,并且远远超出了此范围。

#include <chrono>
#include <iostream>
#include <sstream>

int
main()
{
    using namespace std;
    using namespace std::chrono;

    string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
    istringstream in{s};
    in.exceptions(ios::failbit);
    local_seconds t;
    in >> parse("%a, %d %b %Y %T %z (%Z)", t);
    auto td = floor<days>(t);
    year_month_day ymd{td};
    hh_mm_ss hms{t-td};
    cout << ymd << ' ' << hms << '\n';
    cout << ymd.year() << '\n';
    cout << ymd.month() << '\n';
    cout << ymd.day() << '\n';
    cout << hms.hours() << '\n';
    cout << hms.minutes() << '\n';
    cout << hms.seconds() << '\n';
}

输出:

2020-07-30 00:51:08
2020
Jul
30
0h
51min
8s

首先要注意的是 much 更强的类型安全性。不再需要将所有内容都转换为int来打印出来。而且不再需要转换为int来执行其他操作,例如算术和比较。

例如ymd.year()的类型为std::chrono::year,而不是int。如有必要,可以在这两种表示形式之间进行显式转换。但这通常是不必要的,类似于危险的reinterpret_cast

不再存在诸如1900之类的不直观的偏见,或者在意外的地方不再采用从零开始的计数。

输出通常包括便于调试的单位。

这里解析了" -0700 (PDT)" !这些值未在结果中使用,但必须在其中,否则会出现解析错误。而且,如果您想获取这些值,可以通过非常简单的更改获得它们:

string abbrev;
minutes offset;
in >> parse("%a, %d %b %Y %T %z (%Z)", t, abbrev, offset);
...
cout << offset << '\n';
cout << abbrev << '\n';

现在输出包括:

-420min
PDT

如果需要使用UTC(而不是当地时间)的字段,那是一个简单的更改:

sys_seconds t;

代替:

local_seconds t;

现在,从解析的时间点减去偏移量,以得出UTC time_point(基于std::chrono::time_point的{​​{1}}),并且输出更改为:

system_clock

这使您可以轻松地将本地时间和偏移量解析为2020-07-30 07:51:08 2020 Jul 30 7h 51min 8s

尽管还没有发货(如我所写),但供应商 正在努力实现这一目标。同时,您可以使用free, open-source, header-only C++20 <chrono> preview library来获得此功能,该功能可与C ++ 11/14/17一起使用。只需添加system_clock::time_point#include "date/date.h",一切正常。尽管使用C ++ 11/14,您将需要用using namespace date;代替hh_mm_ss<seconds> hms{t-td};(缺少CTAD)。

答案 1 :(得分:0)

#include <time.h>
char *strptime(const char *buf, const char *format, struct tm *tm);