日期/时间转换:字符串表示到time_t

16

我该如何将格式为"MM-DD-YY HH:MM:SS"的日期字符串转换为C或C++中的time_t值?

7个回答

20

使用strptime()将时间解析为struct tm结构体,然后使用mktime()将其转换为time_t


strptime() 在 Windows 上似乎不可用。有没有好的替代方案? - An̲̳̳drew
不知道Windows上是否有好的替代方案,但有几个开源实现可以使用。 或者,如果您知道日期始终采用提供的格式,可以使用sscanf将其解析为struct tm,然后使用mktime获取time_t。 - Robert Gamble
这里是一个例子 https://dev59.com/k2gu5IYBdhLWcg3wloG_#11213640 - Jaydeep Solanki
@An̲̳̳drew strptime()在Windows上通常可以使用gcc编译器。可用性是编译器问题,而不是操作系统问题。 - chux - Reinstate Monica

4

如果没有 strptime,您可以使用 sscanf 将数据解析为 struct tm,然后调用 mktime。这不是最优雅的解决方案,但它可以工作。


3

需要注意的是,被接受的答案中提到的 strptime 不具备可移植性。下面是我使用的方便的 C++11 代码,用于将字符串转换为 std::time_t:

static std::time_t to_time_t(const std::string& str, bool is_dst = false, const std::string& format = "%Y-%b-%d %H:%M:%S")
{
    std::tm t = {0};
    t.tm_isdst = is_dst ? 1 : 0;
    std::istringstream ss(str);
    ss >> std::get_time(&t, format.c_str());
    return mktime(&t);
}

您可以像这样调用它:
std::time_t t = to_time_t("2018-February-12 23:12:34");

你可以在这里找到字符串格式参数。

  1. 代码没有设置 tm_isdst 成员。不这样做会导致结果不一致。
  2. struct tm 允许初始化其他有益成员。也许可以使用 std::tm t = { 0 };
  3. OP 的月份字符串是数字,而不是字母,请使用 "%m" 而不是 "%b"
  4. OP 使用的顺序与 YMD hms 不同。
- chux - Reinstate Monica
我已经添加了dst选项。用0进行初始化是个好主意。其他的东西可以根据个人需求轻松调整。 - Shital Shah

3

2

很遗憾,在标准的C/C++中没有相关函数。但是,POSIX提供了strptime函数可以将时间转换为struct tm结构体,然后再使用mktime函数将其转换为time_t类型。

如果你需要跨平台兼容性,最好使用boost::date_time库,该库提供了更加复杂的函数来处理这个问题。


1

将格式为“MM-DD-YY HH:MM:SS”的日期字符串转换为time_t的最佳方法

将代码限制为标准C库函数,寻找strftime()的反函数。为了扩展@Rob的一般想法,使用sscanf()

使用"%n"来检测完成的扫描

time_t date_string_to_time(const char *date) {
  struct tm tm = { 0 }; // Important, initialize all members
  int n = 0;
  sscanf(date, "%d-%d-%d %d:%d:%d %n", &tm.tm_mon, &tm.tm_mday, &tm.tm_year,
      &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &n);
  // If scan did not completely succeed or extra junk
  if (n == 0 || date[n]) {
    return (time_t) -1;
  }
  tm.tm_isdst = -1; // Assume local daylight setting per date/time
  tm.tm_mon--;      // Months since January
  // Assume 2 digit year if in the range 2000-2099, else assume year as given
  if (tm.tm_year >= 0 && tm.tm_year < 100) {
    tm.tm_year += 2000;
  }
  tm.tm_year -= 1900; // Years since 1900
  time_t t = mktime(&tm);
  return t;
}

可以使用额外的代码来确保时间戳部分仅为两位数字、正值、间隔等。

注意:这假设“MM-DD-YY HH:MM:SS”是本地时间。


1
有趣的是,我从来没有真正找到过使用“%n”的用例,因为我总是使用* scanf的返回值来确保所有参数都被扫描。然而,它似乎%n(您的使用方式)可以实现这一点,并确保在预期字符串后没有额外的gumpf。现在,我很少学到有关C的新知识了,因此表示赞赏 :-) - paxdiablo
1
@paxdiablo 谢谢。通常情况下," %n" 可以帮助检测到任何必要的尾随文本,而返回值则无法区分。例如:"%d xyz %n" - chux - Reinstate Monica

-1
    static time_t MKTimestamp(int year, int month, int day, int hour, int min, int sec)
{
    time_t rawtime;
    struct tm * timeinfo;

    time ( &rawtime );
    timeinfo = gmtime ( &rawtime );
    timeinfo->tm_year = year-1900 ;
    timeinfo->tm_mon = month-1;
    timeinfo->tm_mday = day;
    timeinfo->tm_hour = hour;
    timeinfo->tm_min = min;
    timeinfo->tm_sec = sec;
    timeinfo->tm_isdst = 0; // disable daylight saving time

    time_t ret = mktime ( timeinfo );

    return ret;
}

 static time_t GetDateTime(const std::string pstr)
{
    try 
    {
        // yyyy-mm-dd
        int m, d, y, h, min;
        std::istringstream istr (pstr);

        istr >> y;
        istr.ignore();
        istr >> m;
        istr.ignore();
        istr >> d;
        istr.ignore();
        istr >> h;
        istr.ignore();
        istr >> min;
        time_t t;

        t=MKTimestamp(y,m,d,h-1,min,0);
        return t;
    }
    catch(...)
    {

    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接