15

I am writing a simple logging class in C++ for learning purposes. My code contains a function that returns a string of today's date. However, I get a compiler error whenever 'localtime' is called.

std::string get_date_string(time_t *time) {
    struct tm *now = localtime(time);
    std::string date = std::to_string(now->tm_mday) + std::to_string(now->tm_mon) + std::to_string(now->tm_year);
    return date;
}

I have tried using #define _CRT_SECURE_NO_WARNINGS. It didn't work and the same error appeared. I also tried putting _CRT_SECURE_NO_WARNINGS inside the preprocessor definitions in the project properties. This gave an unresolved external error.

Does anyone have any ideas on what to do?

ChiefHagno
  • 168
  • 1
  • 1
  • 7
  • 1
    Where is the exact warning message? `localtime` can be dangerous to use because it returns a pointer to a memory area which it owns, so if you call it multiple times you need to make sure each time you copy the struct. Also, by the way, the way you create a string, if you get "2112016" you don't know if that's 21/1/2016 or 2/11/2016. – Klitos Kyriacou Jun 26 '16 at 00:14
  • 1
    **Do not use this function** for the reason given in the warning. – Ben Apr 11 '18 at 11:40

3 Answers3

60

The problem is that std::localtime is not thread-safe because it uses a static buffer (shared between threads). Both POSIX and Windows have safe alternatives: localtime_r and localtime_s.

Here is what I do:

inline std::tm localtime_xp(std::time_t timer)
{
    std::tm bt {};
#if defined(__unix__)
    localtime_r(&timer, &bt);
#elif defined(_MSC_VER)
    localtime_s(&bt, &timer);
#else
    static std::mutex mtx;
    std::lock_guard<std::mutex> lock(mtx);
    bt = *std::localtime(&timer);
#endif
    return bt;
}

// default = "YYYY-MM-DD HH:MM:SS"
inline std::string time_stamp(const std::string& fmt = "%F %T")
{
    auto bt = localtime_xp(std::time(0));
    char buf[64];
    return {buf, std::strftime(buf, sizeof(buf), fmt.c_str(), &bt)};
}
Galik
  • 47,303
  • 4
  • 80
  • 117
2

updated answer with C++20 chrono library

    const auto now            = std::chrono::system_clock::now();
    const auto time_zone      = std::chrono::current_zone();
    const auto local_time     = time_zone->to_local(now);
    const auto time_point     = std::chrono::time_point_cast<std::chrono::days>(local_time);
    const auto year_month_day = std::chrono::year_month_day{ time_point };

    int year  = static_cast<int>(year_month_day.year());
    int month = static_cast<unsigned>(year_month_day.month());
    int day   = static_cast<unsigned>(year_month_day.day());
-2

Try to #define _CRT_SECURE_NO_WARNINGS before #include any other header files, like the following code

#define _CRT_SECURE_NO_WARNINGS
#include <ctime>
//your code
Null
  • 657
  • 2
  • 6
  • 15