How to convert a datetime string with milliseconds to UNIX timestamp - c++

I have the following string
2013-04-12 16:00:15.041
What is the C++ way to convert this string into a 64bit UNIX timestamp? Most question on here deal with only having the timestamp until seconds but in my case I also need to include the milliseconds.

Parse the string into its components and construct a std::chrono::time_point. In C++20, you will have the utc_clock in <chrono>, that is, a utc_time, or else std::chrono::local_t. In C++11 and up, you have std::chrono::system_clock.
There’s sort of a chicken-and-egg problem in converting the broken-down-time into STL time objects, though: usually, doing that gives you your answer with just the C library. You can use std::get_time(), on an istringstream if necessary, to convert your string to a tm and the C standard library function mktime() to convert the tm to a time_t, which you can then pass to std::chrono::system_clock::from_time_t()to convert to a std::chrono::time_point—except that, on UNIX/Linux, time_t is already a UNIX timestamp!
Your example has no time zone specified, so you might or might not need to do time-zone conversion.
The utc_clock uses the same Epoch as POSIX, January 1, 1970, so the time_since_epoch() member function of utc_time/time_point gives you the answer as a std::chrono::duration. If you are using system_clock instead, the Epoch is implementation-defined (but almost always the same Epoch, too), so you will want to find a time_point for 12:00 AM January 1, 1970, and subtract it from the time_point you calculate to get a duration. You can convert this duration, call it moment, into seconds with std::chrono::seconds(moment).count(). You can then convert to int64_t or uint64_t (from <cstdint>) if you want to be sure to have an exactly 64-bit value.
There are a few different UNIX time formats, but if you want to convert your time in milliseconds into a C/POSIX timespec with nanoseconds, rather than the obsolete formats in <sys/time.h>, set .tv_nsec to the number of milliseconds times one million, or convert from std::chrono::milliseconds to std::chrono::nanoseconds.
If the purpose of this is to work with filesystem timestamps, you might want std::filesystem::file_time_type.

Related

C++ : how to get a long value from json and convert it to time_point

I'm quite new to c++ so thera are a bunch of questions I've got but for now this one drives my crazy:
I've ot a json response and want to parse one object as long (because it's a timestamp). After that I want tp parse that long to a time_point object via
chrono::system_clock::from_time_t(...);
So this is what I got for now:
auto last_change_date_long = (long long)json_troubleticket["lastChangeDate"].int_value();
time_t last_change_date_raw = time_t(last_change_date_long);
auto last_change_date = chrono::system_clock::from_time_t(last_change_date_raw);
It compiles, but if i run this (while I know the value for lastChangeDate is 1480702672000) it's result is
2147483647000 ...
Does anyone have a suggestion what went wrong?
This will do it:
auto i = 1480702672000;
std::chrono::system_clock::time_point tp{std::chrono::milliseconds{i}};
Note that the above is not guaranteed to work by the standard because the epoch of system_clock is unspecified. However all implementations are currently using Unix Time, and I have an informal agreement with the implementors that they will not deviate from this while I try to standardize this existing practice.
The reason you're seeing the behavior you have is that your json is counting milliseconds since 1970-01-01 00:00:00 UTC, but time_t typically counts seconds (though that is also not specified by the standard). So at the point where you create last_change_date_raw from last_change_date_long, you're implicitly converting milliseconds to seconds. This would result in a date midway through the year 48891. The implementation of from_time_t is likely freaking out about that (overflowing).
Fwiw, this particular time point represents:
2016-12-02 18:17:52.000 UTC

Add two dates in C++

I'm sure this question is answered elsewhere, but I cannot find it on Google or SO, so here goes.
In C/C++, I want to convert a relative time in format dd-hh:mm:ss provided by
ps -o etime
to an absolute UTC formatted date.
This doesn't seem like it should be very hard. Supposing I have already got a function to produce the relative time stored in struct tm format:
struct tm *starting_rel_time = my_reltime_converstion(...);
time_t t = time(0);
struct tm *current_abs_time = localtime(&t);
what I want is basically the opposite of difftime:
struct *tm starting_abs_time = current_abs_time - starting_rel_time;
Now, I can write my own function to do the conversion, but it's a nightmare because of all the carry operations and special conditions (leap years etc.). Surely there is a way to do this in the C/C++ libraries?
Use Boost::Date_Time libraries.
Convert the DD-HH:MM::SS to seconds with simple math; it's relative-time, so just multiply and add. Then, query the current time() in seconds (assuming it's "relative to now"), and add them. Then use gmtime to convert back to a struct tm.
There is no such language as C/C++.
If you're asking about C, I suggest representing dates internally with a simple numeric type, and converting to and from struct tm only when necessary. If you only need to cover a few decades, then you could use time_t and convert using the standard gmtime and mktime library functions. To cover a wider timespan, you could use a Julian day representation.
If you're asking about C++, I suggest the Boost.Date_Time library. Of course, the C library functions are still available if they meet your needs.
What you're trying to do doesn't make sense. You cannot add two dates.
(And difftime doesn't return a date, nor a time_t.)
In practice, on most, if not all implementations, time_t will be an
integral type with the number of seconds since some specific "epoch".
On such machines, you can add or subtract an integral number of seconds
from a time_t to get a new time, at least if all of the times you're
interested in are in the interval supported by time_t (roughly between
1970 and 2038 on most Unix platforms). This, along with gmtime,
mktime and localtime is probably sufficient for your needs. Note
especially that mktime is required to "correct" it's tm input: you
can, for example, take a tm, add 5 to the field tm_mday, call
mktime on it, and get the correct values for a date five days in the
future—all of the necessary carry operations and special
conditions are handled in mktime.
If this is not sufficient, C++11 has both a time_point and a
duration class, with (from a quick glance) seems to have all of the
functionality you could possibly need.

C++ - How can we get a millisecond timestamp in linux?

How to convert std::chrono::monotonic_clock::now() to milliseconds and cast it to long?
using steady_clock or high_resolution_clock from chrono is also same. I have seen into std::chrono::duration_cast<std::chrono::milliseconds> but I only want the current timestamp and not any duration gaps.
The current timestamp is defined with respect to some point in time (hence it is a duration). For instance, it is "typical" to get a timestamp with respect to the beginning of the Epoch (January 1st 1970, in Unix). You can do that by using time_since_epoch():
namespace chr = std::chrono;
chr::time_point<chr::steady_clock> tp = chr::steady_clock::now();
std::cout << "hours since epoch: "
<< chr::duration_cast<chr::hours>(tp.time_since_epoch()).count()
<< '\n';
To get the value in milliseconds you would need to cast it to std::chrono::milliseconds, instead.
All the built-in clocks have an associated "epoch" which is their base time. The actual date/time of the epoch is not specified, and may vary from clock to clock.
If you just want a number for comparisons then some-clock::now().time_since_epoch() will give you a duration for the time since the epoch for that clock, which you can convert to an integer with the count() member of the duration type. The units of this will depend on the period of the clock. If you want specific units then use duration_cast first:
typedef std::chrono::steady_clock clk;
unsigned long long milliseconds_since_epoch=
std::chrono::duration_cast<std::chrono::milliseconds>(
clk::now().time_since_epoch()).count();
As I said, this is only good for comparisons, not as an absolute time stamp, since the epoch is unspecified.
If you need a UNIX timestamp then you need to use std::chrono::system_clock, which has a to_time_t() function for converting a time_point to a time_t.
Alternatively, you can take a baseline count at a particular point in your program, along with the corresponding time from gettimeofday or something, and then use that to convert relative counts to absolute times.

C++11 number of days since date

I need to store date in flat file. Is there any simple metod to get number of days since particular date (for example since 1 AD) using standard libary in C++11? The only one I know is to:
obtain std::tm structure, set all time values to 0
convert it to std::time_t (I do not know proper method yet)
divide time_t to get the resolution of one day
Can I perform it easier?
What you said sounds reasonable to start with. You can convert the struct tm to time_t using mktime. Note that mktime interprets its input as local time according to the system/environment settings, and there is no UTC counterpart that's as widely available without relying on "extra" libraries, but maybe that's not a problem for you.

Is time_t returned by time() zone specific?

I am just new to <time.h> and have a question regarding to time_t and time().
I read the function time() documented as follows:
time_t time ( time_t * timer ); Get current time
Get the current calendar time as a time_t object.
The function returns this value, and if the argument is not a null
pointer, the value is also set to the object pointed by timer.
The documentation does not talk about time zone.
Thus, for the following C++ code:
time_t t = time(NULL);
If two machines, one in US and the other one in UK, both execute the function call time(NULL) at the same time, will the returned time_t objects be identical?
Will time() returns a value regardless of time zone?
No it's not zone specific. It returns a value that's a count of the number of seconds since 1 Jan 1970 in UTC, ignoring leap seconds. So (in principle) if two machines execute the call at the exact same time, the value returned will be the same, even if they work in two separate time zones.
Well, it's documented to return a time_t - which is documented with:
It is almost universally expected to be an integral value representing the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC. This is due to historical reasons, since it corresponds to a unix timestamp, but is widely implemented in C libraries across all platforms.
So strictly speaking it's not guaranteed cross-platform by the looks of it, but in practice can be treated in a cross-platform way and is in UTC.
(Of course there will be multiple sources of documentation for time_t to start with... I'm not sure what exactly can be deemed definitive here.)
time_t values are independent of time zone differences, as they count time from epoch. If you want to have a local calendar time you can take that time_t value and pass it to the localtime() function, which returns a pointer to struct tm with your local time.
No; this function returns the second count from 00:00:00 UTC on 1 January 1970.
Wikipedia
According to the latest standard of the C programming language issued at 2011:
1. The *time* function determines the current **calendar time**.
2. The encoding of the value is unspecified.
3. The *time* function returns the implementation’s best approximation
to the current calendar time.
where calendar time in terms of the standard represents the current
date (according to the Gregorian calendar) and time in contrast to local
time, which is the calendar time expressed for some specific time zone.
And The range and precision of times representable in clock_t and time_t are implementation-defined.
As a result:
time_t values returned by time() from the C library must be not time zone specific. If it is not true, the C library implementation doesn't comply with standard and this situation can be considered as a bug in library.
time_t value encoding unspecified! It can be specified in the POSIX standard, but definitely not specified in C standard. Due to this you must not rely on the assumptions about its implementation details such as that it counts time in the one second resolution or that it is an integer containing number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC. Use appropriate functions from C Standard Library such as gmtime() and localtime() instead to convert time_t into struct tm and get access to the time stamp details. At least if your application is not considered to be limited only by *NIX systems.
This will give you your "local epoch":
time_t t = time(NULL);
t = timegm(localtime(&t);