How do I construct an ISO 8601 datetime in C++?

C++QtAzure

C++ Problem Overview


I'm working with the Azure REST API and they are using this to create the request body for table storage:

DateTime.UtcNow.ToString("o")

Which produces: >2012-03-02T04:07:34.0218628Z

It is called "round-trip" and apparently it's an ISO standard (see http://en.wikipedia.org/wiki/ISO_8601) but I have no idea how to replicate it after reading the wiki article.

Does anyone know if Boost has support for this, or possibly Qt?

C++ Solutions


Solution 1 - C++

If the time to the nearest second is precise enough, you can use strftime:

#include <ctime>
#include <iostream>

int main() {
    time_t now;
    time(&now);
    char buf[sizeof "2011-10-08T07:07:09Z"];
    strftime(buf, sizeof buf, "%FT%TZ", gmtime(&now));
    // this will work too, if your compiler doesn't support %F or %T:
    //strftime(buf, sizeof buf, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
    std::cout << buf << "\n";
}

If you need more precision, you can use Boost:

#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>

int main() {
    using namespace boost::posix_time;
    ptime t = microsec_clock::universal_time();
    std::cout << to_iso_extended_string(t) << "Z\n";
}

Solution 2 - C++

Using the date library (C++11):

template <class Precision>
string getISOCurrentTimestamp()
{
    auto now = chrono::system_clock::now();
    return date::format("%FT%TZ", date::floor<Precision>(now));
}

Example usage:

cout << getISOCurrentTimestamp<chrono::seconds>();
cout << getISOCurrentTimestamp<chrono::milliseconds>();
cout << getISOCurrentTimestamp<chrono::microseconds>();

Output:

2017-04-28T15:07:37Z
2017-04-28T15:07:37.035Z
2017-04-28T15:07:37.035332Z

Solution 3 - C++

I should point out I am a C++ newb.

I needed string with a UTC ISO 8601 formatted date and time that included milliseconds. I did not have access to boost.

This is more of a hack than a solution, but it worked well enough for me.

std::string getTime()
{
    timeval curTime;
    gettimeofday(&curTime, NULL);

    int milli = curTime.tv_usec / 1000;
    char buf[sizeof "2011-10-08T07:07:09.000Z"];
    char *p = buf + strftime(buf, sizeof buf, "%FT%T", gmtime(&curTime.tv_sec));
    sprintf(p, ".%dZ", milli);

    return buf;
}

The output looks like: 2016-04-13T06:53:15.485Z

Solution 4 - C++

With C++20, time point formatting (to string) is available in the (chrono) standard library. https://en.cppreference.com/w/cpp/chrono/system_clock/formatter

#include <chrono>
#include <format>
#include <iostream>

int main()
{
   const auto now = std::chrono::system_clock::now();
   std::cout << std::format("{:%FT%TZ}", now) << '\n';
}

Output

2021-11-02T15:12:46.0173346Z

It works in Visual Studio 2019 with the latest C++ language version (/std:c++latest).

Solution 5 - C++

Boost has a library for this.

I.e. posix_time has the from_iso_string() and to_iso_string() functions.

Solution 6 - C++

In Qt, that would be:

QDateTime dt = QDateTime::currentDateTime();
dt.setTimeSpec(Qt::UTC);  // or Qt::OffsetFromUTC for offset from UTC
qDebug() << QDateTime::currentDateTime().toString(Qt::ISODate);

Solution 7 - C++

OK so I've modified a few solutions that I've found as came up with the following :

static QString getTimeZoneOffset()
{
    QDateTime dt1 = QDateTime::currentDateTime();
    QDateTime dt2 = dt1.toUTC();
    dt1.setTimeSpec(Qt::UTC);

int offset = dt2.secsTo(dt1) / 3600;
if (offset >= 0)
    return QString("%1").arg(offset).rightJustified(2, '0',true).prepend("+");
return QString("%1").arg(offset).rightJustified(2, '0',true);
}

Then to easily format a date ( yyyy-MM-dd'T'HH:mm:ss.SSSZ ) :

static QString toISO8601ExtendedFormat(QDateTime date)
{
    QString dateAsString = date.toString(Qt::ISODate);
    QString timeOffset =  Define::getTimeZoneOffset();
    qDebug() << "dateAsString :" << dateAsString;
    qDebug() << "timeOffset :" << timeOffset;
    timeOffset = QString(".000%1%2").arg(timeOffset).arg("00");
    qDebug() << "timeOffset replaced :" << timeOffset;
    if(dateAsString.contains("Z",Qt::CaseInsensitive))
        dateAsString = dateAsString.replace("Z",timeOffset);
    else
        dateAsString = dateAsString.append(timeOffset);
        qDebug() << "dateAsString :" << dateAsString;
    return dateAsString;
}

For example GMT +2 would look like this : 2013-10-14T00:00:00.000+0200

Solution 8 - C++

You can use this function which uses std::put_time with a std::ostringstream to generate the resulting std::string.

#include <iostream>
#include <chrono>
#include <iomanip>
#include <sstream>
/**
 * Generate a UTC ISO8601-formatted timestamp
 * and return as std::string
 */
std::string currentISO8601TimeUTC() {
  auto now = std::chrono::system_clock::now();
  auto itt = std::chrono::system_clock::to_time_t(now);
  std::ostringstream ss;
  ss << std::put_time(gmtime(&itt), "%FT%TZ");
  return ss.str();
}
// Usage example
int main() {
    std::cout << currentISO8601TimeUTC() << std::endl;
}

Reference: https://techoverflow.net/2018/03/30/iso8601-utc-time-as-stdstring-using-c11-chrono/

Solution 9 - C++

Tested in Visual C++, GNU C++, Emscripten

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

#if defined (_WIN32) 
#define WINDOWSLIB 1
#elif defined (__APPLE__)//iOS, Mac OS
#define MACOSLIB 1
#elif defined (__LINUX__) || defined(__gnu_linux__) || defined(__linux__) || defined(__linux) || defined(linux)//_Ubuntu - Fedora - Centos - RedHat
#define LINUXLIB 1
#elif defined (__EMSCRIPTEN__)
#define EMSCRIPTENLIB 1
#endif

#define WriteLine(data)std::cout<< data <<std::endl;
typedef std::string String;

String CurrentISO8601DateTime(bool toUTC=true)
{
	using namespace std::chrono;
	system_clock::time_point now = system_clock::now();
	time_t timet = system_clock::to_time_t(now);
	std::tm tm{};
	String localeStr = setlocale(LC_ALL, nullptr);
	setlocale(LC_ALL, u8"");
	String format = String(u8"%FT%T.").append(std::to_string(duration_cast<milliseconds>(now.time_since_epoch()).count() % static_cast<long long>(1000)));
	if (toUTC)
	{
#ifdef WINDOWSLIB
		gmtime_s(&tm, &timet);
#elif LINUXLIB
		gmtime_r(&timet, &tm);
#elif EMSCRIPTENLIB
		gmtime_r(&timet, &tm);
#endif
		format = format.append(u8"Z");
	}
	else
	{
#ifdef WINDOWSLIB
		localtime_s(&tm, &timet);
#elif LINUXLIB
		localtime_r(&timet, &tm);
#elif EMSCRIPTENLIB
		localtime_r(&timet, &tm);
#endif
		format.append(u8"%z");
	}
	String result = String(255, 0);
	const size_t length = std::strftime(&result[0], result.size(), format.c_str(), &tm);
	result.resize(length);
	setlocale(LC_ALL, localeStr.c_str());
	return result;
}

#define ConsoleWriteLn(data) std::cout<< data <<std::endl;

int main()
{
	ConsoleWriteLn(u8"UTC  : " + CurrentISO8601DateTime());
	ConsoleWriteLn(u8"LOCAL: " + CurrentISO8601DateTime(false));
}


Results

UTC : 2020-04-12T17:00:18.632Z
LOCAL: 2020-04-12T12:00:18.633-0500

You can deserialize normally with Json.NET

Solution 10 - C++

You can get local or UTC time:

#include <ctime>
#include <iostream>

int main(){
    std::time_t time = std::time(0); // Get current time

    // Construct local time
    char loc[sizeof("2021-03-01T10:44:10Z")];
    strftime(loc, sizeof(loc), "%FT%TZ", localtime(&time));

    // Construct UTC time 
    char utc[sizeof("2021-03-01T10:44:10Z")];
    strftime(utc, sizeof(utc), "%FT%TZ", gmtime(&time));

    // Print local and UTC time
    std::cout << "Local time: " << loc << std::endl;
    std::cout << "UTC time: " << utc << std::endl;
    return 0;
}

Solution 11 - C++

Did it like this:

using namespace boost::posix_time;
ptime t = microsec_clock::universal_time();
qDebug() << QString::fromStdString(to_iso_extended_string(t) + "0Z"); // need 7 digits

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionchikubaView Question on Stackoverflow
Solution 1 - C++strcatView Answer on Stackoverflow
Solution 2 - C++GillespieView Answer on Stackoverflow
Solution 3 - C++Rahim KhojaView Answer on Stackoverflow
Solution 4 - C++SynckView Answer on Stackoverflow
Solution 5 - C++vinesView Answer on Stackoverflow
Solution 6 - C++Chris BrowetView Answer on Stackoverflow
Solution 7 - C++Danie BruwerView Answer on Stackoverflow
Solution 8 - C++Amir SaniyanView Answer on Stackoverflow
Solution 9 - C++JomaView Answer on Stackoverflow
Solution 10 - C++HBatesView Answer on Stackoverflow
Solution 11 - C++chikubaView Answer on Stackoverflow