How should I proceed to convert std::chrono::minutes::rep type value to hours representation.
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;
int main() {
minutes::rep time = 4;
std::cout << time; // outputs as minutes, need in hours
// duration cast doesn't seems to work here because it
// needs minutes instead of minutes::rep probably
return 0;
}
minutes::rep time = 4;
std::cout << time; // outputs as minutes, need in hours
Because time is just an (implementation-defined) integer type, it has nothing to do with minutes or hours, and doesn't know anything about underlying time representation.
You want to stay in the duration realm:
minutes time{4};
auto as_hours = std::duration_cast<hours>(time);
std::cout << as_hours.count(); // prints 0
Or, likely:
auto as_hours_dbl = std::duration_cast<duration<double, hours::period>>(time);
std::cout << as_hours_dbl.count(); // prints 0.0666667
Related
I am struggling to execute a simple task. I want to take a date parameter from the command line argument and increment it several times by 1 day. The basic program should:
read the command line argument as the starting date, and
loop several times, incrementing that date by 1 day every time.
I convert the char* command line argument to a struct tm, then convert the struct tm to a time_t and add 60 * 60 * 24 = 1 day to it. I convert it back to struct tm to print it.
Here is the code:
#include <iostream>
#include <cstdlib>
#include <string>
#include "time.h"
int main(int argc, char *argv[])
{
char* start_date;
tm tm_start_date = {}; // solution: needs initialization
start_date = argv[1];
strptime(start_date, "%Y-%m-%d", &tm_start_date); // YYYY-MM-DD
char ch_stmt_date[11] = "";
time_t t_stmt_date = 0;
tm tm_stmt_date = {}; // solution: needs initialization;
tm_stmt_date = tm_start_date;
// time_t -> tm localtime_r(time_t, tm)
// tm -> time_t mktime(tm) returns time_t
std::cout << "start_date: " << start_date << " / tm_start_date: " << std::to_string(1900 + tm_start_date.tm_year) + std::to_string(tm_start_date.tm_mon + 1) +
std::to_string(tm_start_date.tm_mday) << std::endl;
// increment by 1 day per iteration
for (int i=0; i<5; i++)
{
// tm -> t_time
t_stmt_date = mktime(&tm_stmt_date);
std::cout << "t_stmt_date: " << t_stmt_date << std::endl;
// + 1 day
t_stmt_date += 60*60*24;
std::cout << "t_stmt_date: " << t_stmt_date << std::endl;
// time_t -> tm
localtime_r(&t_stmt_date, &tm_stmt_date);
strftime (ch_stmt_date, 11, "%Y-%m-%d", &tm_stmt_date);
std::cout << "ch_stmt_date: " << ch_stmt_date << std::endl;
}
return EXIT_SUCCESS;
}
The start date is correctly read and parsed into the struct tm.
However, subsequently I get one of two behaviors of the program:
Either I get a -1 on the first call of t_stmt_date = mktime(&tm_stmt_date); and a value of t_stmt_date: 86399 (1970-01-02) in the output. The rest of the loop then works correctly and iterates 5 times, incrementing 1970-01-02 by 1 day.
Or, the same code using the same command line parameter parses a nonsensical value on the first call of t_stmt_date = mktime(&tm_stmt_date); in the loop which is not a valid date, which, however is also correctly incremented by 60*60*24 on each of the 5 loops.
At this point I am desperate to understand the issue. I am working on Ubuntu 20.04 using gcc.
Thanks for your help.
Edit: Initializing the struct tm did the trick!
[NOTE]
You explicitly mention "using localtime and mktime" in the question's title, but I wasn't sure though after reading the rest of the text if that was mandatory, or you just needed to get a task done.
If you cannot use other libraries, just let me know and I'll remove this answer.
You could use std::chrono and Howard Hinnant's date library (C++11 onwards, header-only).
Or, should you be able to use a C++20 compiler, you would only need std::chrono.
[Demo]
#include <chrono>
#include <iostream> // cout
#include <sstream> // istringstream
#include <string>
#include "date/date.h"
int main()
{
namespace ch = std::chrono;
namespace dt = date;
const std::string start_date{"2022-01-31"}; // date
std::istringstream iss{ start_date }; // to string stream
dt::sys_days start_day{}; // to a time point with a day duration
dt::from_stream(iss, "%Y-%m-%d", start_day);
for (auto day{start_day}, end_day{start_day + dt::days{3}};
day < end_day;
day += dt::days{1}) // with which we can do date arithmetic
{
std::cout << dt::format("%Y-%m-%d\n", day);
}
}
// Outputs:
//
// 2022-01-31
// 2022-02-01
// 2022-02-02
I'm working on a logging system for my console, and I'm trying to get a timestamp for when a entry was added to the log. I tried doing this;
time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
char time_buffer[16] = { 0 };
std::strftime(time_buffer, sizeof(time_buffer), "%H.%M.%S", std::localtime(&now));
TextWrapped(time_buffer);
This almost works. The issue is that this works more as a clock then as a timestamp as it will not stay at the time of when the entry was logged, but increment... I think that I might have to use std::chrono::time_point, but I didn't really understand how to use it.
In C++20 there are a number of nice functions in std::chrono to do this:
#include <iostream>
#include <chrono>
#include <format>
int main()
{
// get the current time
auto now = std::chrono::system_clock::now();
// floor till the start of day
auto start_of_day = std::chrono::floor<std::chrono::days>(now);
// round time till nearest seconds
auto time_since_start_of_day = std::chrono::round<std::chrono::seconds>(now - start_of_day);
// convert to hour minute second type
std::chrono::hh_mm_ss hms { time_since_start_of_day };
std::cout << time_since_start_of_day << "\n"; // will output number of seconds since start of day
std::cout << hms << "\n"; // will output formatted time in hh:mm::ss
auto string = std::format("{}", hms);
std::cout << string << "\n"; // will output formatted time in hh:mm::ss
return 0;
}
So I figured it out.
The issue is that since my code snipped is in my render function, it will always update. My fix was to move the snippet above into my "add_log()" function, then write those timestamps into a new array, then in my for loop I would just grab from both arrays.
Kinda like so;
for (int i = 0; i < items.Size; i++) {
TextWrapped(items[i]);
TextWrapped(timestamps[i]);
}
It's a hacky solution, but it works.
I have a bunch of tasks which are in the order of microseconds, the below code prints only until seconds (Thu Oct 21 12:48:20 2021) so comparing the values of start and finish always ends up giving 0. I want to be able to compare in the order of milliseconds and microseconds. Is there a function to help with this?
Also, is there a way to convert uint64_t current1 = std::chrono::system_clock::now().time_since_epoch().count(); to time_t to print out the current time based on the count()?
const auto p1 = std::chrono::system_clock::now();
std::time_t now = std::chrono::system_clock::to_time_t(p1);
std::cout << "now: " << std::ctime(&now);
I recommend skipping the C timing API entirely. It is error-prone and doesn't handle sub-second precision.
If UTC (as opposed to local time) is ok, then there is a header-only, open-source preview of C++20 that works with C++11/14/17:
#include "date/date.h"
#include <chrono>
#include <iostream>
int
main()
{
using date::operator<<;
const auto p1 = std::chrono::system_clock::now();
std::cout << "now: " << p1 << '\n';
}
Output:
now: 2021-10-21 20:28:15.754423
To port the above program to C++20 (which is already shipping in the latest Visual Studio), just drop the #include "date/date.h" and using date::operator<<;.
If you need local time, that can be also be had in C++20 (shipping in VS), but the open-source preview of C++20 is no longer header only. There exists one source file that needs to be compiled, and depending on your needs, might require a download of the IANA tz database.
#include "date/tz.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
const auto p1 = system_clock::now();
std::cout << "now: " << zoned_time{current_zone(), p1} << '\n';
}
Output:
now: 2021-10-21 16:28:15.754423 EDT
The above syntax assumes C++17. For C++11/14 the template parameter for zoned_time needs to be specified: zoned_time<system_clock::duration>.
The above program ports to C++20 by dropping #include "date/tz.h" and using namespace date;.
In either program you can truncate to millisecond precision with:
const auto p1 = floor<milliseconds>(system_clock::now());
time_t is usually an integer specifying (whole) seconds.
You could get the millseconds by subtracting the whole-second time_t from now:
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
p1 - std::chrono::system_clock::from_time_t(now)).count();
or using operator%:
auto ms = std::chrono::time_point_cast<std::chrono::milliseconds>p1)
.time_since_epoch() % std::chrono::seconds(1);
std::cout << ms.count();
Example how you could do the formatting:
#include <chrono>
#include <iostream>
#include <iomanip>
int main() {
using Clock = std::chrono::system_clock;
using Precision = std::chrono::milliseconds;
auto time_point = Clock::now();
// extract std::time_t from time_point
std::time_t t = Clock::to_time_t(time_point);
// output the part supported by std::tm
std::cout << std::put_time(std::localtime(&t), "%FT%T."); // select format here
// get duration since epoch
auto dur = time_point.time_since_epoch();
// extract the sub second part from the duration since epoch
auto ss =
std::chrono::duration_cast<Precision>(dur) % std::chrono::seconds{1};
// output the millisecond part
std::cout << std::setfill('0') << std::setw(3) << ss.count();
}
Let's say, I have following duration value:
auto duration=12h+15min+99s+99ms;
I want to know how many hours that is (as double value).
When I do auto hours=std::chrono::duration_cast<std::chrono::hours>(duration), I get hours.count() which is int. What is the right way to get the value for the whole duration expressed as double?
using namespace std::chrono;
// Create a double-based hours duration unit
using dhours = duration<double, hours::period>;
// Assign your integral-based duration to it
dhours h = 12h+15min+99s+99ms;
// Get the value
cout << h.count();
Or alternatively, simply divide your integral based duration by one double-based hours:
cout << (12h+15min+99s+99ms)/1.0h << '\n';
#include<iostream>
#include<chrono>
using namespace std::chrono_literals;
int main() {
auto duration = 12.0h+15min+99s+99ms;
std::cout << std::chrono::duration_cast<std::chrono::duration<long double,std::ratio<3600,1>>>(duration).count();
}
I have a starting timepoint in milliseconds like so:
using namespace std::chrono;
typedef time_point<system_clock, milliseconds> MyTimePoint;
MyTimePoint startTimePoint = time_point_cast<MyTimePoint::duration>(system_clock::time_point(steady_clock::now()));
Now I will have a certain number of hours that I want to add or subtract to the startTimePoint.
int numHours = -5//or 5 etc (Can be a plus or minus number)
How can I add this abount of time to the original startTimePoint??
If you want to add five hours to startTimePoint, it's boringly simple:
startTimePoint += hours(5); // from the alias std::chrono::hours
Live example.
By the way, you're trying to convert a steady_clock::now() into a system_clock::time_point, which shouldn't even compile. Change the steady_clock::now() to system_clock::now() and you should be good to go.
Here I have used time in minutes you can go for anything that you want from the user.
So the below is the simple programme using chrono
#include <iostream>
#include <chrono>
using namespace std;
int main() {
using clock = std::chrono::system_clock;
clock::time_point nowp = clock::now();
cout<<"Enter the time that you want to add in minutes"<<endl;
int time_min;
cin>>time_min;
cin.ignore();
clock::time_point end = nowp + std::chrono::minutes(time_min);
time_t nowt = clock::to_time_t ( nowp );
time_t endt = clock::to_time_t ( end);
std::cout << " " << ctime(&nowt) << "\n";
std::cout << ctime(&endt) << std::endl;
return 0;
}
Convert time_point to duration or duration to time_point without intermediate.
It is inherently impossible to convert a time_point to duration or back directly.
Many examples use time_t as intermediate, which is a fine method.
I use the method that uses the time_point 'zero' as a helper.
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
int main(int argc, char *argv[])
{
using namespace std::chrono;
system_clock::time_point zero; // initialised to zero in constructor
system_clock::time_point tp_now; // now as time_point
duration<int, ratio<1>> dur_now; // now as duration
system_clock::time_point tp_future; // calculated future as time_point
// The objective is to sleep_until the system time is at the next 5 minutes
// boundary (e.g. time is 09:35)
tp_now = system_clock::now(); // What time is it now?
cout << "tp_now = " << tp_now.time_since_epoch().count() << endl;
// It is not possible to assign a time_point directly to a duration.
// but the difference between two time_points can be cast to duration
dur_now = duration_cast<seconds>(tp_now-zero); // subtract nothing from time_point
cout << "dur_now = " << dur_now.count() << endl;
// Instead of using seconds granularity, I want to use 5 minutes
// so I define a suitable type: 5 minutes in seconds
typedef duration<int,ratio<5*60>> dur5min;
// When assigning the time_point (ok: duration) is truncated to the nearest 5min
dur5min min5 = duration_cast<dur5min>(tp_now-zero); // (Yes, I do it from time_point again)
cout << "min5 ('now' in 5min units) = " << min5.count() << endl;
// The next 5 min time point is
min5 += dur5min{1};
cout << "min5 += dur5min{1} = " << min5.count() << endl;
// It is not possible to assign a duration directly to a time_point.
// but I can add a duration to a time_point directly
tp_future = zero + min5;
cout << "tp_future = " << tp_future.time_since_epoch().count() << endl;
// to be used in e.g. sleep_until
// std::this_thread::sleep_until(tp_future);
return 0;
}
Thanks to Carsten's solution I managed to create function:
#include <chrono>
auto getTimeDurationMovedWith(std::chrono::hours hours2move)
{
using namespace std::chrono;
auto current_time = system_clock::now();
decltype(current_time) zeroTime; // no better solution to move time found in stackoverflow
return chrono::duration_cast<microseconds>(
current_time - zeroTime + hours(hours2move));
}
And it can be used like that:
auto tmp = getTimeDurationMovedWith(chrono::hours(-10));
cout << tmp.count() << endl;