100

I have been upgrading some old code and have been trying to update to c++11 where possible. The following code is how I used to display the time and date in my program

#include <iostream>
#include <string>
#include <stdio.h>
#include <time.h>

const std::string return_current_time_and_date() const
{
    time_t now = time(0);
    struct tm tstruct;
    char buf[80];
    tstruct = *localtime(&now);
    strftime(buf, sizeof(buf), "%Y-%m-%d %X", &tstruct);
    return buf;
}

I would like to output the current time and date in a similar format using std::chrono(or similar) but am unsure how to go about doing so. Any help would be greatly appreciated. Thanks

Jonas
  • 6,915
  • 8
  • 35
  • 53
const_ref
  • 4,016
  • 3
  • 23
  • 38
  • Please lookup if there's already such a question asked and if not then ask. – legends2k Jun 20 '13 at 20:28
  • *Possible Duplicate:* http://stackoverflow.com/questions/12346260/c-date-and-time – legends2k Jun 20 '13 at 20:29
  • 4
    You're not going to get much better with C++11. chrono is more about timing (how long did something take) than time-of-day type stuff. You might check out Boost Date Time, though. It has more robust date&time functionality. – Nathan Ernst Jun 20 '13 at 20:30
  • Get date&time using chrono and output? See the [first example](http://en.cppreference.com/w/cpp/chrono/time_point). – dyp Jun 20 '13 at 20:41
  • 2
    @DyP That looks promising but I need to return a string from the function and not sure how to go about doing so with std::put_time – const_ref Jun 20 '13 at 20:42
  • Lookout on std::localtime or std::gmtime those functions aren't thread safe! – Gelldur Oct 28 '18 at 11:52
  • Related: https://stackoverflow.com/q/70684900/1201614 – luca Jan 15 '22 at 10:03

9 Answers9

134

The <chrono> library only deals with time and not dates, except for the system_clock which has the ability to convert its timepoints to time_t. So using <chrono> for dates will not improve things much. Hopefully we get something like chrono::date in the not too distant future.

That said, you can use <chrono> in the following way:

#include <chrono>  // chrono::system_clock
#include <ctime>   // localtime
#include <sstream> // stringstream
#include <iomanip> // put_time
#include <string>  // string

std::string return_current_time_and_date()
{
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);

    std::stringstream ss;
    ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X");
    return ss.str();
}

Note that std::localtime may cause data races. localtime_r or similar functions may be available on your platforms.

Update:

Using a new version of Howard Hinnant's date library you can write:

#include "date.h"
#include <chrono>
#include <string>
#include <sstream>

std::string return_current_time_and_date() {
  auto now = std::chrono::system_clock::now();
  auto today = date::floor<days>(now);

  std::stringstream ss;
  ss << today << ' ' << date::make_time(now - today) << " UTC";
  return ss.str();
}

This will print out something like "2015-07-24 05:15:34.043473124 UTC".


On an unrelated note, returning const objects has become undesirable with C++11; const return values cannot be moved from. I also removed the trailing const because trailing const is only valid for member functions and this function has no need to be a member.

bames53
  • 86,085
  • 15
  • 179
  • 244
  • 9
    Beware that some old compilers might not recognize `std::put_time`. Once I tried to compile my code that had `std::put_time` on CentOS 7 using g++, it failed. Status of `std::put_time` support in GCC http://stackoverflow.com/q/14136833/4694036 – Eddie Jul 25 '15 at 05:09
  • 1
    is there C++ function similar to std::put_time but to return string? – Nick Oct 15 '15 at 07:18
  • @Nick No. The C function `strftime` will let you fill a buffer with a C string. The obsoleted function `asctime` will return a C string in a fixed time format. – bames53 Oct 15 '15 at 07:29
  • thanks, well i guess you can do put_time with string stream – Nick Oct 15 '15 at 12:37
  • Refering to the update using Hinnant's date library: Under MSVC2015 I needed to put a `using namespace date;` right before using the `<<` operator for the `days` type in order to compile. – yau Jun 13 '17 at 18:38
  • @yau you could use `date::days` instead – Nik Jul 13 '17 at 09:13
  • 4
    if you don't use `using namespace date;` the `<< today` will not work. – Orwellophile Nov 01 '17 at 14:57
36

Here's a C++20 solution:

#include <chrono>
#include <format>

std::string get_current_time_and_date()
{
    auto const time = std::chrono::current_zone()
        ->to_local(std::chrono::system_clock::now());
    return std::format("{:%Y-%m-%d %X}", time);
}

std::chrono::time_zone::to_local converts a system clock time point (std::chrono::time_point<std::chrono::system_clock, TDuration>) to a local time point (std::chrono::local_time<TDuration>). This local time point can then be formatted using std::format with formatting options similar to strftime.

Currently, only MSVC has implemented std::format. The calendar and timezone additions to chrono are currently "partially" implemented by Clang and GCC, but check here for the updated status: https://en.cppreference.com/w/cpp/compiler_support. For more information about the chrono library, read here: https://en.cppreference.com/w/cpp/chrono.

Victor Eijkhout
  • 5,088
  • 2
  • 22
  • 23
Björn Sundin
  • 691
  • 7
  • 10
  • Does clang or gcc implement the timezone part of the `` library? Even if we drop `std::format` from the example, can the above code be tested in Godbolt or Wandbox? – Andrzej Jan 25 '22 at 17:06
  • The easiest way to find out would be by... testing it in Godbolt or Wandbox. – Björn Sundin Jan 26 '22 at 18:09
  • Actually, I guess I could add that information to the answer to make it more complete. Thanks – Björn Sundin Jan 26 '22 at 18:15
  • Sadly, doesn’t work with gcc 11 or clang 13 or, really, any compiler I tried on Compiler Explorer. – Adam Getchell Mar 17 '22 at 04:53
  • calling `to_local()` in MSVC produces a huge memory leak – Molochnik Jul 21 '22 at 05:49
  • "" file not found, "current_zone" is not a member of std::chrono... What's the heck with C++20 and compilers? (we are in 2023 now). – Adrian Maire Mar 22 '23 at 20:54
  • This works with "gcc (trunk)", "clang (trunk)" and the latest MSVC release on compiler explorer now, so we should expect all three compilers to support these features pretty soon I think :) – Björn Sundin Mar 25 '23 at 10:38
18

An example:

#include <iostream>
#include <chrono>
#include <ctime>

std::string getTimeStr(){
    std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());

    std::string s(30, '\0');
    std::strftime(&s[0], s.size(), "%Y-%m-%d %H:%M:%S", std::localtime(&now));
    return s;
}
int main(){

    std::cout<<getTimeStr()<<std::endl;
    return 0;

}

Output as below:

enter image description here

Jayhello
  • 5,931
  • 3
  • 49
  • 56
  • 5
    NOT THREAD SAFE see [Data races](http://www.cplusplus.com/reference/ctime/localtime/) – Gelldur Jan 04 '20 at 11:51
  • 10
    Downvote: The current answer returns a 30-character long string with lots of null characters on the end. If you attempt to concatenate something to it, it will not work. I did suggest an edit to make it work, but it was rejected by Django programmers.... – Den-Jason Sep 26 '20 at 16:58
7

For getting also milliseconds, I use chrono and C function localtime_r which is thread-safe (in opposition to std::localtime).

#include <iostream>
#include <chrono>
#include <ctime>
#include <time.h>
#include <iomanip>


int main() {
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
  std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
  std::chrono::milliseconds now2 = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
  struct tm currentLocalTime;
  localtime_r(&currentTime, &currentLocalTime);
  char timeBuffer[80];
  std::size_t charCount { std::strftime( timeBuffer, 80,
                                         "%D %T",
                                          &currentLocalTime)
                         };

  if (charCount == 0) return -1;

  std::cout << timeBuffer << "." << std::setfill('0') << std::setw(3) << now2.count() % 1000 << std::endl;
  return 0;
}

For format: http://www.cplusplus.com/reference/ctime/strftime/

rodolk
  • 5,606
  • 3
  • 28
  • 34
  • Since you're already importing iomanip, you can skip creating your own buffer by using std::put_time instead of std::strftime. – Bloodgain Nov 14 '19 at 22:14
  • You may appear off by half a second, since `to_time_t` may truncate, but might also round. – Ruslan Nov 20 '19 at 19:01
  • Don't you have to apply a clock type template argument? ``std::chrono::system_clock::time_point now = std::chrono::system_clock::now();`` – trozzel Dec 08 '21 at 13:46
5

bames53 solutions are good, but do not compile on my VS2017. The solution with ctime does not compile because localtime is very deprecated. The one with date.h does not compile with the current date.h I just took off github even though the documentation says they should, because today cannot be streamed as is. I omitted the includes but here is code that works:

void TimeTest()
{
    auto n = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(n);
    std::tm buf;
    localtime_s(&buf, &in_time_t);
    std::cout << std::put_time(&buf, "%Y-%m-%d %X") << std::endl;

}

// I just added date.h from this link's guthub to the project.
// https://howardhinnant.github.io/date/date.html
void TimeTest1() {
    auto now = std::chrono::system_clock::now();
    auto today =  floor<date::days>(std::chrono::system_clock::now());
    std::cout << date::year_month_day{ today } << ' ' << date::make_time(now - today) << std::endl;
}

// output is 
// 2018-04-08 21:19:49
// 2018-04-08 18:19:49.8408289

Feel free to fix bames53 solution and delete mine. My text just won't fit in a comment. I'm sure it can save many people from grief.

Yaniv
  • 504
  • 4
  • 10
  • 1
    If you add `using date::operator<<;` you can stream `today` without converting it to `year_month_day`. – Howard Hinnant Apr 08 '18 at 23:24
  • Howard, thank you so much for writing and sharing this library. To the point, I'd rather never use using as I've suffered bugs and ambiguity from namespace collisions enough in my days. Also, if we are being precise I'd like to note that the first example outputs local time while the second is universal time. – Yaniv Apr 10 '18 at 14:06
  • 1
    Glad I can help. `usings` at function scope are a good compromise since conflicts are easier to control when they occur. I realize this isn't perfect, but it is the best that can be done for stream insertion operators for std::types, written by 3rd party libraries. But just last month I convinced the C++ committee to place this streaming operator in `namespace std::chrono` for C++20 so that it will be found by ADL. Then it will no longer require a `using`. – Howard Hinnant Apr 10 '18 at 14:21
  • Good observation about the output being UTC. Also available is a higher-level library that provides operations with local time. That can be with your computer's current local time zone, or with a specifically designated time zone (e.g. "America/New_York"). Here is the [documentation for the time zone library](https://howardhinnant.github.io/date/tz.html). – Howard Hinnant Apr 10 '18 at 14:24
  • @HowardHinnant: we're still missing your `operator<<` in the standard. Can you please give a status? – davidhigh Apr 25 '21 at 18:52
  • 1
    It is in C++20: http://eel.is/c++draft/time.clock.system.nonmembers#4 Vendors are at work implementing it. – Howard Hinnant Apr 25 '21 at 19:19
5

The fmt library has the ability to format tm structures: it has the same spec as strftime.

#include <ctime>
#include <fmt/chrono.h>

std::string current_datetime(void)
{
  std::time_t tt = std::time(nullptr);
  std::tm *tm = std::localtime(&tt);
  return fmt::format("{:%Y%m%d}", *tm);
}
vitaut
  • 49,672
  • 25
  • 199
  • 336
Gang Liang
  • 793
  • 1
  • 9
  • 19
3

Although correct answers were already given, I decided to implement one more solution that outputs also fractional part of second.

You may notice in my code that sometimes I subtract one second from time_t value, - std::chrono::seconds(1), it is because according to documentation to_time_t() may round value instead of truncating (according to doc "If std::time_t has lower precision, it is implementation-defined whether the value is rounded or truncated"), hence I have to subtract 1 second to make it truncated time.

Try it online!

#include <chrono>
#include <string>
#include <sstream>
#include <iomanip>

std::string FormatTime(std::chrono::system_clock::time_point tp) {
    std::stringstream ss;
    auto t = std::chrono::system_clock::to_time_t(tp);
    auto tp2 = std::chrono::system_clock::from_time_t(t);
    if (tp2 > tp)
        t = std::chrono::system_clock::to_time_t(tp - std::chrono::seconds(1));
    ss  << std::put_time(std::localtime(&t), "%Y-%m-%d %T")
        << "." << std::setfill('0') << std::setw(3)
        << (std::chrono::duration_cast<std::chrono::milliseconds>(
           tp.time_since_epoch()).count() % 1000);
    return ss.str();
}

std::string CurrentTimeStr() {
    return FormatTime(std::chrono::system_clock::now());
}

#include <iostream>

int main() {
    std::cout << CurrentTimeStr() << std::endl;
}

Example Output:

2021-12-02 04:10:51.876

As suggested by @AndyK, starting from C++20 you can use std::chrono::current_zone() and its method to_local(), they return std::chrono::local_time which is directly convertible to your desired string format by outputting to std::ostringstream or through std::format(). Whole function becomes very short:

#include <chrono>
#include <string>
#include <sstream>
#include <iostream>

std::string CurrentTimeStr() {
    return (std::ostringstream{} << std::chrono::current_zone()->to_local(
        std::chrono::system_clock::now())).str().substr(0, 23);
}

int main() {
    std::cout << CurrentTimeStr() << std::endl;
}

But right now not all compilers support this current_zone() function, online GodBolt servers failed to compile it on trunk CLang and GCC, but MSVC compiles it well. Although my local laptop installation of CLang compiled it too.

Arty
  • 14,883
  • 6
  • 36
  • 69
  • This is equivalent and a bit briefer: std::string CurrentTimeStr() { using namespace std::chrono; auto tp = system_clock::now(); auto us = duration_cast(tp.time_since_epoch()).count() % 1000000; return std::format("{:%Y-%m-%d %T}.{:06}", current_zone()->to_local(tp), us); } – AndyK Apr 25 '22 at 17:08
  • The format should be {:%Y-%m-%d %X}. My code is of course for microseconds, rather than milliseconds - cast to milliseconds and use {:03} to format for milliseconds. – AndyK Apr 25 '22 at 17:40
  • @AndyK Even if your code works correctly, still I couldn't test it because `std::format` and `std::chrono::current_zone()` are both not yet implemented in most recent versions of CLang and GCC, [see online link](https://godbolt.org/z/vh8cv4sfG) you may see that CLang/GCC can't compile it. – Arty Apr 26 '22 at 10:00
  • @AndyK On online latest MSVC compiler it comiles, [see online here](https://godbolt.org/z/Yf7fT9a8P), but throws an exception at runtime `The specified module could not be found.`. So also needs probably some tweaking of MSVC compiler. – Arty Apr 26 '22 at 10:07
  • 1
    @AndyK On my local home laptop your MSVC version works correctly! So great, you have a nice solution! You may post it as a separate answer to this question, not only in comments to my answer. BTW, if I use `%T` instead of `%X` as so `{:%Y-%m-%d %T}` then it already outputs 7 digits after dot, no need for extra `.{:06}`, you may just resize final string to smaller one if you need less digits. – Arty Apr 26 '22 at 10:17
  • @AndyK Thanks for suggestion! Updated my answer and included your `current_zone()` function usage in my second code snippet. Also made code even much more shorter than you suggested. – Arty Apr 26 '22 at 11:00
  • I didn't know about that .{06} tweak. Thanks for that. I still find chrono hard to get to grips with! I did this on my local Visual Studio install using the latest C++ language spec - should have mentioned that. Sorry. – AndyK Apr 28 '22 at 08:07
2

You can improve the answer from @bames53 by using Boost lexical_cast instead of string stream manipulations.

Here is what I do:

#include <boost/lexical_cast.hpp>
#include <ctime>

std::string return_current_time_and_date() {
    auto current_time = std::time(0);
    return boost::lexical_cast<std::string>(std::put_time(std::gmtime(& current_time), "%Y-%m-%d %X"));
}
Xavier Lamorlette
  • 1,152
  • 1
  • 12
  • 20
-1

This is the best and the simplest way in my opinion to print the current time:

string setCurrentDate() {
        time_t currentTime{time(nullptr)};
        string date = ctime(&currentTime);
        return date;
    }

time() functions takes a pointer to time_t variable to store the current time in this variable(You can pass the nullptr also).

ctime() functions takes a pointer to time_t variable to convert it to a string representation(a human-readable ASCII string).

Note: The ctime() function appends a newline character ('\n') at the end of the string

if you print the returned date, it will be something like that:

Tue Aug 01 02:11:31 2023
  • While this would be a good answer for someone explicitly **not** wanting to use chrono, this answer is in the wrong place. – SimonC Aug 10 '23 at 12:18