pixelou
pixelou

Reputation: 804

Build/parse UTC date using standard library

I'm having troubles building a UTC date in c++ using the standard library. For example (any is fine):

or parsing

Conditions:

The best candidates so far are:

How can I build an std::chrono::time_point::time_point from the UTC date?

Upvotes: 3

Views: 1724

Answers (2)

Howard Hinnant
Howard Hinnant

Reputation: 218750

How can I build a std::chrono::system_clock::time_point from the UTC date?

Just for this part of it, here is a header-only high-performance C++11/14 modern solution. It can be used like this:

int y = 2016;
int m = 1;
int d = 14;
int h = 18;
int min = 2;
int sec = 15;
std::chrono::system_clock::time_point tp = 
    date::sys_days{date::year{y}/m/d} +
    std::chrono::hours{h} +
    std::chrono::minutes{m} +
    std::chrono::seconds{sec};

This is an open source, free library on github. Here is a video presentation of the library. This library is portable to all recent implementations of C++11 and C++14 (including VS2013 and VS2015). It offers a better interface than tm inherited from C, and a greater range of validity. It also offers higher performance, and a great deal of compile-time abilities in C++14. It is designed to be a simple extension of <chrono>, and is thus fully interoperable with <chrono>.

For parsing, use tz.h:

01/01/1970 00:00:00 UTC

#include "tz.h"
#include <iostream>
#include <sstream>

int
main()
{
    std::istringstream in{"01/01/1970 00:00:00 UTC"};
    date::sys_seconds tp;
    date::parse(in, "%d/%m/%Y %T %Z", tp);
    using namespace date;
    if (!in.fail())
        std::cout << tp << '\n';
}

In the above code, sys_seconds is a std::chrono::time_point<system_clock, seconds>.

01/01/1970 00:00:00 +0000

Change %Z to %zabove.

01/01/1970 00:00:00

Remove the %Z/%z.

  • avoid external libraries if possible

Sorry, but otherwise you have to:

  • messing around with std::tm directly,...

This library allows you to parse both %z and %Z. You can throw away the abbreviation, or discover it, and try to figure out what it means (in general the abbreviation is ambiguous). With %z the offset will alter the parsed value to give you UTC:

std::istringstream in{"01/01/1970 00:00:00 +0500"};
date::sys_seconds tp;
date::parse(in, "%d/%m/%Y %T %z", tp);
using namespace date;
if (!in.fail())
    std::cout << tp << '\n';

Output:

1969-12-31 19:00:00

If you would rather get the local time, that is easy too:

std::istringstream in{"01/01/1970 00:00:00 +0500"};
date::local_seconds tp;
date::parse(in, "%d/%m/%Y %T %z", tp);
using namespace date;
if (!in.fail())
    std::cout << tp << '\n';

Output:

1970-01-01 00:00:00

local_seconds is a std::chrono::time_point, but based on a "clock" which has no now().

Upvotes: 2

SKZ 81
SKZ 81

Reputation: 323

Better use std::tm... As it is standard.

Don't worry about tm_zone. It's an optional field, only available in some environment like Linux/GNU or freeBSD... (actually, it comes with glibc, as you pointed out).

It as, nevertheless NO functionnal effect. A program using it should have a #ifndef or #ifdef directive to embed the statement, allowing compilation on systems without the field defined in the structure.

To answer your last question... Unsure of your your needs, but a starting point can be :

system_clock::time_point tp = system_clock::now();

as found here :

http://www.cplusplus.com/reference/chrono/time_point/time_since_epoch/

Hope it helps,

PS : throw an eye on this : Difference between steady_clock vs system_clock?

Upvotes: 0

Related Questions