Time Stamp Question - c++

I got a time stamp string as this 3.44063E+08. How can I convert it to normal time, such as 12:10:22, etc.

The numeric value is a time_t, you need to convert it to local or Greenwhich time which localtime() or gmtime(), respectively, after which you can use strftime() to print in a format you choose.
Here is a quick and complete example:
edd#max:/tmp$ cat timeformat.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
time_t tt = 3.44063E+08;
struct tm tm;
char buf[32];
tm = *localtime(&tt);
strftime(buf, 31, "%Y-%m-%d %H:%M:%S", &tm);
printf("%s\n", buf);
return 0;
}
edd#max:/tmp$ gcc -o timeformat timeformat.c
edd#max:/tmp$ ./timeformat
1980-11-25 23:03:20
edd#max:/tmp$
Edit: And as you tagged your question C++, have a look at Boost Date_Time which has a lot to offer to. But as my example showed, for the simple 'number to text' conversion, you do not need it.

A timestamp in exponential format means that someone was using floating point time counters and wasn't paying attention when they wrote the code to print it. If all you have is that piece of text, you're not going to be able to convert it to an accurate time, since it's only accurate to 1000 seconds (about 20 minutes). If you actually have the original as a double, you can get an accurate time from it. If you have it as a float, god help you.
The number is (probably) a time_t, which is a count of seconds since the Unix epoch (1 January 1970). You can convert it to a broken-down time structure (year, month, etc) using gmtime() or localtime(), and then to whatever text format you want using strftime(). If you only have the text rather than an actual number, you'll have to parse it to a number first using strtod().

A lot more context would be useful, but assuming you already have it, 3.44063E+08 is 344063000 which, as a time_t converts to 1980-11-26 05:03:20 (utc). If that makes sense to you as a timestamp, then it is a time_t: number of seconds since 1970-01-01.
Another possibility is that it came from Excel or another Microsoft Office product, which stores dates as days since 1900, or 1899 in some cases. That converts to some date in the year 943,893. If that makes sense, like if you are doing astronomical or slow radioisotope calculations, etc., then it is early in the day, about 03:42.

Related

How do I make "days-since-epoch" values play nice with std::chrono?

I'm obtaining from a magical gremlin an array of non-negative integer values in memory, say of type I. Each of these represents a number of days since some epoch (which is many years before 0 in the ISO 8601 calendar).
Now, I want to wrap these values - essentially through pointer or reinterpretation - by C++ classes, which can interact well with the code of std::chrono, or perhaps I should say be used with code which normally takes std::chrono timepoints and durations.
What would be my best course of action for this? Note I don't want to replace any data in the array nor create a new value for each of the existing ones, elsewhere.
Each of these represents a number of days since the epoch (which is many years before 0 in the ISO 8601 calendar).
Let's say you're referring to the epoch for the Julian Day Number. This epoch is consistent with your description. The link says this epoch is November 24, 4714 BC, in the proleptic Gregorian calendar. Instead of using the "BC" system, I find it convenient to use a system with negative years instead so that there is a smooth mathematical transition across the year 0. In this system the epoch is November 24, -4713.
Using Howard Hinnant's free, open-source, header-only date library, this is very easy to do. If I've got the wrong epoch, just substitute in the correct one in the obvious place.
#include "date/date.h"
#include <iostream>
date::sys_days
to_sys_days(int i)
{
using namespace date;
return sys_days{days{i} -
(sys_days{1970_y/January/1} - sys_days{-4713_y/November/24})};
}
The date::sys_days return type is a std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<int, std::ratio<86400>>>. Or in English: it is a system_clock-based time_point with a precision of days. This time_point will implicitly convert to your platform's system_clock::time_point.
Now you can pass your int to to_sys_days, and pass the result to a function taking a system_clock::time_point. For example:
void
display(std::chrono::system_clock::time_point tp)
{
using date::operator<<;
std::cout << tp << '\n';
}
int
main()
{
display(to_sys_days(2'458'674));
}
This outputs:
2019-07-09 00:00:00.000000
to_sys_days is a very cheap operation. You can afford to do it each time you read a single element of the data. All it does is subtract 2440588 from i. The optimized machine code for to_sys_days (clang++ -O3) is literally:
leal -2440588(%rdi), %eax
I.e. all of the type-changing business happens at compile-time. It's free. The only thing that happens at run-time is the epoch offset adjustment. This is the bare minimum that must be done no matter what to align your epoch with the system_clock epoch.
So if you have an array of int as your data, you don't have to make a copy of the entire array. You just transform each element of it on demand. For example:
int
main()
{
int data[] = {2'458'674, 2'458'675, 2'458'676, 2'458'677, 2'458'678};
for (auto i : data)
display(to_sys_days(i));
}
Output:
2019-07-09 00:00:00.000000
2019-07-10 00:00:00.000000
2019-07-11 00:00:00.000000
2019-07-12 00:00:00.000000
2019-07-13 00:00:00.000000
If you don't want to use the date library, you can still get the job done, it is just a bit more work.
First create a duration type that means days:
using days = std::chrono::duration
<int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;
Then figure out the number of days between 1970-01-01 and your epoch.
Then take your integral value i, wrap it in days, and subtract off your epoch difference. Then you can construct a system_clock::time_point with your value of days.
Note: It is important that you do the epoch adjustment in units of days as opposed to converting first to the units of system_clock::time_point and then doing the adjustment. This latter strategy will overflow on some platforms. You are protected from overflow if you do the epoch offset in days precision.
I strongly advise against using the reinterpret_cast tool to get this job done. It seems both unnecessary and dangerous.
Update
I forgot about the part that says the Julian Day epoch is noon instead of midnight. If you want to take this into account, it is very easy with the date lib:
auto
to_sys_days(int i)
{
using namespace date;
using namespace std::chrono;
return sys_time<hours>{days{i} -
(sys_days{1970_y/January/1} - sys_days{-4713_y/November/24} - 12h)};
}
I simply subtracted 12 hours off the epoch difference and let auto deduce the return type for me (which is now a system_clock-based time_point with a precision of hours).
The exact same display function with the same input now outputs:
2019-07-09 12:00:00.000000
If it's really just about the duration then you can simply do
std::chrono::days(integer_value);
and you will get a chrono duration type.

How to convert a datetime string with milliseconds to UNIX timestamp

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.

How to get the local current time in seconds since epoch in C++ (MSVS)?

I need the local (with timezone offset) current time in seconds since epoch. The following code looks a bit clumzy because it creates an intermediate temporary structure tm which is superfluous. Why do I have to get time_t then convert it to tm in order to return to time_t? Is there a better way?
time_t ct = time(0);
tm lct = tm();
localtime_s(&lct, &ct);
ct = _mkgmtime(&lct);
If you want to get the local time (with time zone and DST applied) in portable C, then yes, it's generally a two-step procedure: starting with your time-since-the-epoch, first call localtime, then do something with the resulting broken-down struct tm. (Usually what I do next is call strftime.)
You can also call ctime to get a local time string directly.
The reason there are a lot of different function calls involved is that, unfortunately, there are several different time formats in use. (And the reason for that is that dates and times are complicated!) You can represent time as seconds-since-1970. You can represent it as a struct tm. You can represent it as a string (in one of several zillion formats). In Unix and Linux, you can represent it as a struct timeval or a struct timespec.
But one thing there isn't a straightforward or standard way to do, as you've discovered, is get local time as seconds-since-1970. But the reason for that is that it's not a very useful representation. In general, there are two things you might want to do with a date/time value: (1) perform computations on it or (2) display it to the user. If you want to display it to the user, you probably want to display it in local time, so there are lots of ways of converting to local time in human-readable format in any format you want. (As I said, the usual way is to call localtime, then strftime.) But if you want to perform computations, really the only way to do those is using seconds-since-1970 in UTC, because that makes all the other hairy problems go away. How many days are there in the month? Is it a leap year? What time zone are we in? Is daylight saving time in effect?
If you try to represent local time as seconds-since-1970, though, you're probably fibbing. For example, right now, the time is 1460383736, which is 14:08:56 UTC. Where I'm sitting, that's 10:08:56 EDT (U.S. Eastern time, DST in effect). So I suppose I could say that's 1460369336 seconds since 1970, local time. But, again where I'm sitting, 1460369336 seconds ago was not midnight on January 1, 1970 -- it was actually 11 pm on December 31, 1969. It's off by an hour, and the reason is that DST was not in effect on January 1, 1970.
So, bottom line, I would encourage you to rethink the way you're handling local times, because while it's possible to compute this "seconds-since-1970 as local time" value, it's an odd thing to do, and it's likely to cause you various problems which will be much harder to work around than if you used a more straightforward scheme.
But, if you really want to, here are two ways you might be able to determine the offset between UTC and local time, without calling gmtime or _mkgmtime:
Call localtime, and look at the tm_gmtoff field. (Unfortunately, this field is nonstandard, and not present on all systems.)
Call the obsolete ftime function, and look at the timezone field of struct timeb. (Here there are several gotchas: not only is ftime obsolete and nonstandard, but the timezone field is in minutes, and it's positive for zones west of Greenwich, while tm_gmtoff is negative.)
But, anyway, those would more or less directly give you the number to add to or subtract from your UTC seconds-since-1970 value to get "local" seconds-since-1970.
Here is a way to do this computation using the C++11/14 <chrono> library plus this free, open-source timezone library to do the conversion to local time.
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
auto now = floor<seconds>(system_clock::now());
auto s = current_zone()->to_local(now) - local_days{1970_y/jan/1};
cout << s.count() << '\n';
}
You first discover your current IANA timezone with current_zone(). Then you get the current time with system_clock::now() and truncate it to seconds. Next you can convert that to your local time, and then subtract the result from any epoch you desire (1970-01-01 in this example).
The result is of type std::chrono::seconds.
All this being said, I share the same reservations about doing this as described in Steve Summit's answer.
If you instead decide to represent the timestamp as a string, that is also easily done:
auto now = make_zoned(current_zone(), floor<seconds>(system_clock::now()));
auto str = format("%F %T %z", now);
str has type std::string. This just output for me:
2016-04-11 11:42:50 -0400
which is my current local time (truncated to seconds), and my current local UTC offset.
If in the future you decide that seconds-precision is too coarse, you can easily change the above code to any other precision by just changing one line:
floor<milliseconds>(system_clock::now());
and now the contents of str would look like:
2016-04-11 11:42:50.368 -0400

Convert number of seconds to time

Is there a way to convert the number of seconds (e.g. 3056144 sec, this is time delta not a time) to time in format YYYY-mm-dd HH:MM:SS?
I've tried to convert number of seconds to struct tm using localtime and then substract UNIX start time (1970-01-01), but this is not working as expected.
Thanks in advance.
P.S. I have to use C++03, not C++11.
If using Boost.Date_Time is an option for you, this might be what you're looking for:
#include <boost/date_time.hpp>
using boost::posix_time::seconds;
using boost::posix_time::to_simple_string;
std::cout << to_simple_string(seconds(3056144)) << std::endl;
This will print:
848:55:44
However, as you can see in the output above, it will not tell you how many years have passed. This is for good reason, because a year has not always 365 days.
If you're converting a time delta to ISO 8601-like time, you just need to offset your timedelta by the number of seconds since 1907-01-01 that corresponds to your 0 (start) time, then use localtime to convert to a struct tm.
Due to the fact that the number of days per month depends on which month and year it is, trying to convert delta seconds to any larger time units than days without considering where the start and end times are on the actual calendar is going to be fraught with errors.
Like Bathsheba mentions, it depends on how accurate you need to be.
I've seen some algorithms duck the issue that simply assuming a month is 30 days (and therefore a year is only 360 days). If that's what you want to do, then trying to use localtime ill be more trouble than it's worth.
If you want to do it "exactly" right, you have to convert your start and end times to actual aligned-to-the-epoch time_t values, and use some kind of calendar-aware date computation to work out the time between the two. localtime isn't going to cut it (and that's not even considering how it would be an hour off id the timedelta crosses a DST boundary).

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.