【问题标题】:strptime() equivalent on Windows?Windows 上的 strptime() 等价物?
【发布时间】:2010-09-24 05:23:58
【问题描述】:

是否有适用于 Windows 的 strptime() 的良好等效实现?不幸的是,这个 POSIX 函数似乎不可用。

Open Group description of strptime - 总结:它将诸如"MM-DD-YYYY HH:MM:SS"之类的文本字符串转换为tm struct,与strftime()相反。

【问题讨论】:

  • 如果你添加了 strptime 的描述会有所帮助,这样我就不必用谷歌搜索了 :)

标签: c++ c windows datetime


【解决方案1】:

如果您不想移植任何代码或谴责您的项目进行提升,您可以这样做:

  1. 使用sscanf解析日期
  2. 然后将整数复制到 struct tm 中(从月份减去 1,从年份减去 1900 - 月份是 0-11,年份从 1900 开始)
  3. 最后,使用mktime 获取UTC 纪元整数

请记住将struct tmisdst 成员设置为-1,否则您将遇到夏令时问题。

【讨论】:

  • 注意,mktime 适用于 1970 ~ 2038 范围内的日期,但您可以使用 _mktime64 适用于 1970 ~ 3000 范围内的日期 :)
  • 有时用当前值填充isdst 是有意义的,您可以使用localtime(&current_time)->tm_isdst; 获取它,其中current_timetime_t 格式的当前时间,由time(&current_time) 返回.
  • @amwinter tm_wday 和 tm_yday 怎么样?
  • @aderchox 只需使用 mktime() 标准化时间,您将获得正确的 tm_wday 和 tm_yday。
  • 广告 2. 如果 sscan 直接进入 &t.tm_day 则不需要 记得将结构初始化为零 例如:struct tm my_time{0};
【解决方案2】:

假设您使用的是 Visual Studio 2015 或更高版本,您可以将其用作 strptime 的替代品:

#include <time.h>
#include <iomanip>
#include <sstream>

extern "C" char* strptime(const char* s,
                          const char* f,
                          struct tm* tm) {
  // Isn't the C++ standard lib nice? std::get_time is defined such that its
  // format parameters are the exact same as strptime. Of course, we have to
  // create a string stream first, and imbue it with the current C locale, and
  // we also have to make sure we return the right things if it fails, or
  // if it succeeds, but this is still far simpler an implementation than any
  // of the versions in any of the C standard libraries.
  std::istringstream input(s);
  input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
  input >> std::get_time(tm, f);
  if (input.fail()) {
    return nullptr;
  }
  return (char*)(s + input.tellg());
}

请注意,对于跨平台应用程序,std::get_time 直到 GCC 5.1 才实现,因此切换到直接调用 std::get_time 可能不是一种选择。

【讨论】:

  • 感谢您的可复制粘贴。
  • 但是 std::get_time 在 VS2015 here 上被破坏了@
  • 它没有坏;他们试图做的事情也不适用于 GCC 或 Clang,虽然我没有专门测试过,但它可能也不适用于 strptime。
  • +1 但要让它工作,我需要在get_time() 行之后添加以下行:if(input.eof()) return (char *)(s + strlen(s));
  • 这两者(GCC11 和 2021 年末的 glibc 和 STL)之间的行为有所不同:此 C++ 版本拒绝 strptime("2018-11-41", "%Y-%m-%d", x),返回 nullptr,而 C 版本成功,离开尾随 "1" 未解析。
【解决方案3】:

strptime() 的开源版本(BSD 许可证)可在此处找到:http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/time/strptime.c?rev=HEAD

您需要添加以下声明才能使用它:

char *strptime(const char * __restrict, const char * __restrict, struct tm * __restrict);

【讨论】:

  • Visual Studio 2008 抱怨“致命错误 C1083:无法打开包含文件:'sys/cdefs.h':没有这样的文件或目录”
  • 公认的答案如何。它使用了一堆不包含在 windows 中的标题。
  • 此解决方案不适用于 Windows(在 Linux 或 macOS 上不需要!)
【解决方案4】:

这样就可以了:

#include "stdafx.h"
#include "boost/date_time/posix_time/posix_time.hpp"
using namespace boost::posix_time;

int _tmain(int argc, _TCHAR* argv[])
{
    std::string ts("2002-01-20 23:59:59.000");
    ptime t(time_from_string(ts));
    tm pt_tm = to_tm( t );

但是请注意,输入字符串是 YYYY-MM-DD

【讨论】:

    【解决方案5】:

    另一种方法是使用GetSystemTime 并将时间信息发送到一个函数,该函数使用vsnprintf_s 根据您的格式对其进行解析。在里面 下面的示例有一个函数可以创建一个毫秒的时间字符串 精确。然后它将字符串发送到一个函数,该函数根据所需的格式对其进行格式化:

    #include <string>
    #include <cstdio>
    #include <cstdarg>
    #include <atlstr.h> 
    
    std::string FormatToISO8601 (const std::string FmtS, ...) {
       CStringA BufferString;
       try {
           va_list VaList;
           va_start (VaList, FmtS);
           BufferString.FormatV (FmtS.c_str(), VaList);
       } catch (...) {}
       return std::string (BufferString);
    }
    
    void CreateISO8601String () {
       SYSTEMTIME st;
       GetSystemTime(&st);
       std::string MyISO8601String = FormatToISO8601 ("%4u-%02u-%02uT%02u:%02u:%02u.%03u", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
    }
    

    【讨论】:

    • 你搞错了。问题是寻求一种将字符串表示 转换为struct tm 的方法,而您已经提出了strftime 的(较差的)实现。
    猜你喜欢
    • 2023-03-11
    • 2021-06-22
    • 2014-01-03
    • 2010-11-15
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    • 2014-08-24
    相关资源
    最近更新 更多