Skip to content
C++ Better Explained
Go back
How to Get the Current Date and Time in C++

How to Get the Current Date and Time in C++

Printing today’s date sounds like it should be one line. In C++ it takes three, because the language separates measuring time from interpreting it as a human calendar date — and once you see why, the API stops feeling awkward.


The Short Answer

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

int main() {
    auto now = std::chrono::system_clock::now();
    std::time_t t = std::chrono::system_clock::to_time_t(now);

    std::cout << std::put_time(std::localtime(&t), "%Y-%m-%d %H:%M:%S") << "\n";

    return 0;
}

Output:

2026-08-25 14:30:07

Compile with g++ -std=c++11 main.cpp. That is the whole recipe — the rest of this article explains what each piece is doing so you can change it confidently.


The Three Steps, Explained

Step 1: system_clock::now() returns a time_point — a count of ticks since an arbitrary starting instant called the epoch. It is a precise number, not a date. system_clock specifically is the clock tied to real-world wall time, which is why it is the right one here (steady_clock, covered in measuring execution time, is the one for stopwatches).

Step 2: to_time_t converts that time point into a std::time_t, the older C-style representation: seconds since 1 January 1970 UTC. This is the bridge into the C time functions, which is where the calendar formatting lives.

Step 3: std::localtime takes that count of seconds and breaks it apart into a std::tm struct with separate fields for year, month, day, hour, and so on — adjusted to your machine’s time zone. std::put_time then renders that struct using a format string.

The separation exists because seconds-since-1970 is unambiguous and easy to compare, while “the 25th of August” depends on where you are standing. C++ makes you name that conversion explicitly.

If you're looking to go deeper with C++, the C++ Better Explained Ebook is perfect for you — whether you're a complete beginner or looking to solidify your understanding. Just $19.

Format Codes You Will Actually Use

put_time uses the same codes as C’s strftime:

CodeMeaningExample
%YYear, 4 digits2026
%mMonth, 01–1208
%dDay, 01–3125
%HHour, 00–2314
%MMinute, 00–5930
%SSecond, 00–5907
%AWeekday nameTuesday
%BMonth nameAugust
%pAM or PMPM
%IHour, 01–1202

Mix them freely:

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

int main() {
    auto now = std::chrono::system_clock::now();
    std::time_t t = std::chrono::system_clock::to_time_t(now);
    std::tm* local = std::localtime(&t);

    std::cout << std::put_time(local, "%Y-%m-%d")              << "\n";
    std::cout << std::put_time(local, "%d/%m/%Y")              << "\n";
    std::cout << std::put_time(local, "%A, %B %d, %Y")         << "\n";
    std::cout << std::put_time(local, "%I:%M %p")              << "\n";

    return 0;
}

Output:

2026-08-25
25/08/2026
Tuesday, August 25, 2026
02:30 PM

Reading Individual Fields

If you need the year as a number rather than as text, pull it out of the std::tm struct directly — but two of its fields have surprising offsets:

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

int main() {
    auto now = std::chrono::system_clock::now();
    std::time_t t = std::chrono::system_clock::to_time_t(now);
    std::tm* local = std::localtime(&t);

    int year  = local->tm_year + 1900;   // tm_year counts from 1900
    int month = local->tm_mon + 1;       // tm_mon is 0-based: 0 = January
    int day   = local->tm_mday;          // tm_mday is 1-based, no adjustment

    std::cout << "Year: "  << year  << "\n";
    std::cout << "Month: " << month << "\n";
    std::cout << "Day: "   << day   << "\n";

    return 0;
}

tm_year + 1900 and tm_mon + 1 are inherited from 1970s C and catch out nearly everyone the first time. tm_mday, inconsistently, is already 1-based. When in doubt, prefer put_time — it applies these adjustments for you.


Local Time vs UTC

Swap one function to get UTC instead:

std::cout << "Local: " << std::put_time(std::localtime(&t), "%Y-%m-%d %H:%M:%S") << "\n";
std::cout << "UTC:   " << std::put_time(std::gmtime(&t),    "%Y-%m-%d %H:%M:%S") << "\n";

Use localtime for anything a person reads on their own machine. Use gmtime for log files, database records, and anything that will be compared against timestamps from another computer — UTC has no time zones and no daylight saving jumps, so it never goes backwards by an hour.

One caution: localtime and gmtime return a pointer to a single shared internal buffer. Calling one overwrites the result of the other, and neither is thread-safe. If you need to keep a tm, copy it: std::tm copy = *std::localtime(&t);.


A Practical Use: Timestamped Filenames

Building a log filename from the current time is the most common real reason to reach for this:

#include <iostream>
#include <fstream>
#include <sstream>
#include <chrono>
#include <ctime>
#include <iomanip>

std::string timestamp() {
    auto now = std::chrono::system_clock::now();
    std::time_t t = std::chrono::system_clock::to_time_t(now);

    std::ostringstream oss;
    oss << std::put_time(std::localtime(&t), "%Y%m%d_%H%M%S");
    return oss.str();
}

int main() {
    std::string filename = "log_" + timestamp() + ".txt";
    std::cout << "Writing to " << filename << "\n";

    std::ofstream file(filename);
    if (file) {
        file << "Log started\n";
        file.close();
    }

    return 0;
}

Output:

Writing to log_20260825_143007.txt

The trick is ostringstream: put_time writes to a stream, so send it to a string stream instead of std::cout and pull the text back out with .str(). The %Y%m%d_%H%M%S layout is deliberate — timestamps in that order sort alphabetically into chronological order, so your log files line up correctly in any file listing.


What About C++20?

C++20 added std::chrono::year_month_day and calendar-aware formatting with std::format, which finally removes the detour through C:

// C++20, with recent compiler support
auto today = std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now());
std::cout << std::format("{:%Y-%m-%d}", today) << "\n";

It is cleaner, but compiler support for <format> arrived late and unevenly. The put_time approach above works everywhere from C++11 onward, which makes it the safer thing to learn first.



Take Your C++ Further

If you’re looking to go deeper with C++, the C++ Better Explained Ebook is perfect for you — whether you’re a complete beginner or looking to solidify your understanding. Just $19.

👉 Get the C++ Better Explained Ebook — $19

📋

Free Download: The 10 Mistakes Every C++ Beginner Makes

A free 1-page checklist that shows the exact traps that slow down every C++ beginner — so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


Share this post on:

Written by

Sahil Bora

Software Engineer. Author and creator of C++ Better Explained.


Previous Post
Binary Tree in C++: Build One From Scratch With Full Code
Next Post
C++ deque Explained: When to Use It Instead of vector

Keep Learning