7

我想要一个函数,该函数将采用 time_t 参数和任意格式字符串并对其进行格式化。我想要这样的东西:

std::string GetTimeAsString(std::string formatString, time_t theTime)
{
    struct tm *timeinfo;
    timeinfo = localtime( &theTime);

    char buffer[100];
    strftime(buffer, 100, formatString.c_str(), timeinfo);
    std::string result(buffer);
    return result;
}

然而,我遇到的一个问题是缓冲区长度。我正在考虑使用 formatString * 4 作为缓冲区长度。但我猜你不能动态设置缓冲区长度?也许我可以选择一个任意大的缓冲区?对于如何使其通用,我有点困惑。

我该如何编写一个函数来实现这一点?

4

5 回答 5

5

如果你有 C++11:

std::string GetTimeAsString(std::string formatString, time_t theTime)
{
    struct tm *timeinfo;
    timeinfo = localtime( &theTime);

    formatString += '\a'; //force at least one character in the result
    std::string buffer;
    buffer.resize(formatstring.size());
    int len = strftime(&buffer[0], buffer.size(), formatString.c_str(), timeinfo);
    while (len == 0) {
        buffer.resize(buffer.size()*2);
        len = strftime(&buffer[0], buffer.size(), formatString.c_str(), timeinfo);
    } 
    buffer.resize(len-1); //remove that trailing '\a'
    return buffer;
}

请注意,我将 formatString 作为 const 引用(为了速度和安全性),并将结果字符串用作缓冲区,这比稍后进行额外的复制要快。我也从与格式字符串相同的大小开始,每次尝试将大小加倍,但这很容易更改为更适合 strftime 结果的内容。

于 2011-10-28T22:44:59.207 回答
3

使用 avector<char>作为缓冲区而不是数组。反复增加大小,直到strftime返回非零。

于 2011-10-28T22:32:03.310 回答
3

C++11 解决方案std::put_time()

std::string GetTimeAsString(std::string formatString, time_t theTime)
{
    struct tm* timeinfo = localtime(&theTime);

    std::ostringstream os;
    os << std::put_time(timeinfo, formatString.c_str());
    return os.str();
}
于 2018-11-08T15:25:30.397 回答
2

我认为您最好的选择是提供一个可能处理绝大多数情况的固定缓冲区,然后对其余情况进行特殊处理。类似的东西(未经测试,除了我头骨内的湿件):

std::string GetTimeAsString (std::string formatString, time_t theTime) {
    struct tm *timeinfo;
    char buffer[100], *pBuff = buffer;
    int rc, buffSize = 100;

    timeinfo = localtime (&theTime);
    rc = strftime(pBuff, 100, formatString.c_str(), timeinfo);

    // Most times, we shouldn't enter this loop.

    while (rc == 0) {
        // Free previous in it was allocated.

        if (pBuff != buffer)
            delete[] pBuff;

        // Try with larger buffer.

        buffSize += 100;
        pBuff = new char [buffSize];
        rc = strftime(pBuff, buffSize, formatString.c_str(), timeinfo);
    }

    // Make string then free buffer if it was allocated.

    std::string result(pBuff);
    if (pBuff != buffer)
        delete[] pBuff;

    return result;
}

strftime如果提供的缓冲区不够大,将返回零。在这种情况下,您开始分配更大的缓冲区,直到合适为止。

您的未分配缓冲区大小和用于分配大小的增量可以根据您的需要进行调整。这种方法的优点是除了极少数情况外,您不会注意到效率损失(无论它可能有多小) - 绝大多数情况下都不会进行分配。

此外,您可以选择其他一些方法(例如,+10%、加倍等)来增加缓冲区大小。

于 2011-10-28T22:34:41.723 回答
0

如果缓冲区的大小太小而无法容纳预期结果,则 strftime() 函数将返回 0。使用此属性,您可以在堆上分配缓冲区并尝试 2 的连续幂作为其大小:1、2、4、8、16 等,直到缓冲区足够大。使用 2 的幂的优点是解决方案的复杂性与结果的长度成对数比例。

还有一种特殊情况需要考虑:格式可能使得结果的大小始终为 0(例如空格式)。不知道如何处理。

于 2011-10-28T22:36:18.630 回答