Convert number of seconds to time - c++

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).

Related

Using time_t filttering

I'd like to understand better time_t since i've never dealt with it before.
I want to make a filter_by_time function that gets a time window (lets say, 24 hours) and sends me back a vector of objects with a lower time gap of the said time window.
So since the function is getting a integer (from what i googled i understand i might need long-int) how can i convert the current time and the time_t field of an object into a long int ?
I was thinking to check if the current time (now) minus object's time_t < 24 hours then i'd put object into the array
hope i could be clear enough with my ambitions
Actually the time_t is almost always an integer counting the seconds since 00:00, Jan 1 1970 UTC (POSIX time).
However, this is not defined by the standard and might not be 100% reliable everywhere.
You can try to use from_time_t to convert your time_t to a time_point and use the constructors of time_point and duration to construct another time point from your integer. Then you can compare those time points.
This would be the most reliable way of solving the problem without assuming any particular format for time time_t.
But if it is acceptable for you to assume that the time_t is always POSIX time, you might also be able to just substract the integers as you have already suggested.

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

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++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.

Time Stamp Question

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.