c ++ Функция для форматирования time_t как std :: string: длина буфера? - PullRequest
5 голосов
/ 29 октября 2011

Мне нужна функция, которая будет принимать параметр 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 в качестве длины буфера.Но я думаю, вы не можете динамически установить длину буфера?Может быть, я мог бы выбрать произвольно большой буфер?Я немного застрял в том, как сделать его универсальным.

Как мне написать функцию для достижения этой цели?

Ответы [ 5 ]

4 голосов
/ 29 октября 2011

Если у вас есть 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 в качестве константной ссылки (для скорости и безопасности) и использую результирующую строку в качестве буфера, что быстрее, чем делать дополнительную копию позже. Я также начинаю с того же размера, что и строка формата, и удваиваю размер при каждой попытке, но это легко можно изменить на что-то более подходящее для результатов strftime.

3 голосов
/ 29 октября 2011

Используйте vector<char> для буфера вместо массива. Повторно увеличивайте размер, пока strftime не станет ненулевым.

2 голосов
/ 29 октября 2011

Я думаю, что вам лучше всего было бы предоставить фиксированный буфер, который, вероятно, будет обрабатывать подавляющее большинство случаев, а затем сделать специальную обработку для остальных. Нечто подобное (непроверенное, за исключением влажной посуды внутри моего черепа):

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%, удвоение и т. Д.) Для увеличения размера буфера.

1 голос
/ 08 ноября 2018

C ++ 11 решение с std::put_time():

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

    std::ostringstream os;
    os << std::put_time(timeinfo, formatString.c_str());
    return os.str();
}
0 голосов
/ 29 октября 2011

Функция strftime () возвращает 0, если размер буфера слишком мал, чтобы содержать ожидаемый результат. Используя это свойство, вы можете выделить буфер в куче и использовать последовательные степени 2 как его размер: 1, 2, 4, 8, 16 и т. Д., Пока буфер не станет достаточно большим. Преимущество использования степеней 2 состоит в том, что сложность решения логарифмически пропорциональна длине результата.

Существует также особый случай, о котором нужно подумать: формат может быть таким, что размер результата всегда будет равен 0 (например, пустой формат). Не уверен, как справиться с этим.

...