How do I write a message timestamp to a log file? - c++

I'm trying to create a logging file for my C++ program. My goal is to put two timestamps at two points of my program and print in a file the CPU time period between these two points. I'm doing this because I want to know which parts of my code are the most time consuming so I can make improvements (so there may be several chunks of code I want to measure). So far, I've made a function that, when called, prints a string that I pass as an argument, to a file:
#define LOGFILE "myprog.log"
void Log (std::string message){
std::ofstream ofs;
ofs.open(LOGFILE, std::ofstream::out | std::ios::app);
ofs << message << std::endl;
ofs.close();
}
However, I'm having difficulty figuring out how to print the CPU timestamp. Firstly, I don't know what time measurement format I should use (should I use the chrono or the time_t types?) I'm trying to print a time period so it would be helpful if there was a type for duration (I've tried chrono::duration but it seems to require C++11 support). Secondly, given I know what type to use, how do I print it to the file? Is there a way to cast that type to a string? Or can I pass it directly to my function and print it somehow?
This has troubled me a lot the last couple of days and I can't seem to figure it out, so any input would be really helpful. Thanks in advance!

Get a CPU Timestamp
You'll want to use std::chrono::system_clock to get this timestamp. Do not use std::chrono::steady_clock or std::chrono::high_resolution_clock, as those are for making high-precision timing measurements, and do not guarantee fidelity or accuracy to wall-clock time.
auto now = std::chrono::system_clock::now();
//now is a time_point object describing the instant it was recorded according to your system clock
Print this CPU Timestamp in a readable format
In C++20, this is pretty trivial.
std::string formatted_time = std::format("{0:%F_%T}", now);
ofs << formatted_time << ": " << message << std::endl;
%F is a substitute for %Y-%m-%D, which will output year-month-day in ISO format, i.e. 2018-10-09.
%T is the same for %H:%M:%S, which will output a time, i.e. 17:55:34.786
See the specification for std::format and std::formatter for more information about how to specify these parameters.
As of December 2020, no major compilers support the <format> library, yet, so as an alternative you can use fmt, which is a standalone implementation of the library.
Prior to C++20
Consider Howard Hinnant's date library, most of which is being incorporated into C++20 as a new part of the chrono library. The format function found in that library uses the same syntax as suggested above for the C++20 version, although without integration with std::format.

I'm usually use my implementation for such things.
#include <chrono>
#include <ctime>
// strftime format
#define LOGGER_PRETTY_TIME_FORMAT "%Y-%m-%d %H:%M:%S"
// printf format
#define LOGGER_PRETTY_MS_FORMAT ".%03d"
// convert current time to milliseconds since unix epoch
template <typename T>
static int to_ms(const std::chrono::time_point<T>& tp)
{
using namespace std::chrono;
auto dur = tp.time_since_epoch();
return static_cast<int>(duration_cast<milliseconds>(dur).count());
}
// format it in two parts: main part with date and time and part with milliseconds
static std::string pretty_time()
{
auto tp = std::chrono::system_clock::now();
std::time_t current_time = std::chrono::system_clock::to_time_t(tp);
// this function use static global pointer. so it is not thread safe solution
std::tm* time_info = std::localtime(&current_time);
char buffer[128];
int string_size = strftime(
buffer, sizeof(buffer),
LOGGER_PRETTY_TIME_FORMAT,
time_info
);
int ms = to_ms(tp) % 1000;
string_size += std::snprintf(
buffer + string_size, sizeof(buffer) - string_size,
LOGGER_PRETTY_MS_FORMAT, ms
);
return std::string(buffer, buffer + string_size);
}
It returns current time in format: 2018-09-23 21:58:52.642.
Yes it requires --std=c++11 or above.

For the record:
If C++20 features are not available, as in my case, you can use the following:
#include <ctime>
#include <iomanip>
#include <iostream>
using namespace std ;
time_t now = time(nullptr) ;
cout << put_time(localtime(&now), "%T") << endl ;
put_time is defined in iomanip library, look at https://en.cppreference.com/w/cpp/io/manip/put_time, and time_t and localtime are from the ctime, https://en.cppreference.com/w/cpp/chrono/c/ctime

If you want a more manual approach, this is what I've used before
char buffer[MAX_BUFFER_SIZE];
time_t t = time(NULL);
struct tm *lt = localtime(&t);
snprintf(buffer, MAX_BUFFER_SIZE, "%02d/%02d/%02d %02d:%02d:%02d", lt->tm_mon+1, lt->tm_mday, lt->tm_year%100, lt->tm_hour, lt->tm_min, lt->tm_sec);
Then just output buffer, which now contains string representation of time, to your file.

Related

Conversion of date from human-readable format to epoch fails

I'd like to create a program that converts the date of a specific human-readable format to epoch.
So far I have the following code the first part of which creates this human-readable format and the second one converts it to epoch.
#include <time.h>
#include <iostream>
#include <ctime>
#include <string>
#include <cstring>
using namespace std;
int main(int argc, char const *argv[])
{
time_t timeNow;
struct tm *ltm = NULL;
time(&timeNow);
ltm = localtime(&timeNow);
char buffer[100];
strftime(buffer, sizeof(buffer), "%c %Z", ltm);
cout << "human readable timestamp is " << buffer << endl;
std::tm tmNow;
memset(&tmNow, 0, sizeof(tmNow));
strptime(buffer, "%c %Z", &tmNow);
cout << "epoch timestamp is " << mktime(&tmNow) << endl;
return 0;
}
So the printouts I get are the following :
human readable timestamp is Thu Sep 16 10:23:06 2021 EEST
epoch timestamp is 1631780586
My time zone is EEST as one can see but the epoch one is wrong because it is one hour ahead. The correct should have been 1631776986. I assume I'm doing wrong something with the local time. I've found third-party libraries examples like boost or poco that do this conversion, but I'd prefer the above conversion to be done by using native C++.
Does anyone see what I'm missing?
The C timing/calendrical API is very difficult to use correctly (which is why C++ is moving away from it).
From the C standard:
The value of tm_isdst is positive if Daylight Saving Time is in effect, zero if Daylight Saving Time is not in effect, and negative if the information is not available.
Set tmNow.tm_isdst = -1; prior to the call to mktime.

How to deal with time in C++

I have a question about managing the date and time in c++. I have two classes Plane and Flight in my program.
My Plane will consist data as:
string tailNumber;//Plane's unique trait
vector<vector<string>> planeSchedule;//2D string vector to contain plane's depature date and arrival date
My Flight class will consist data as:
string tailNumber;//Plane's unique trait
string departureDate;
string arrivalDate;
In my main class, I will input the value for departureDate and arrivalDate in format: "YYYY/MM/DD HH:MM" such as: "2019/04/15 10:30" and "2019/04/16 9:30" (I will use the 24-hour format and time will be GMT).
My question is how do I convert the two strings above to a proper format to store in my planeSchedule, so that I will be able to avoid the time conflict in the planeSchedule.
For example, If the next time I'm adding a flight with departure and arrival date beetween the: 2019/04/15 10:30" and "2019/04/16 9:30" such as: "2019/04/15 13:30" and "2019/04/16 7:30", I will get an error like "Flight conflict, plane is not available to flight."
My professor recommends using an unsigned long int to store time, but I really do not know where to start to solve this problem. Any help/suggestion is appreciated.
The go-to place regarding dates and times in C++ is <chrono>. Some of it has been with us since C++11, some of it we'll see coming with C++20. It works in conjunction with the C-style date and time utilities in <ctime>, which might even suffice for your purposes.
Trying to handle date / time as either integers or strings, parsing them from input, comparing, and converting them to strings for output, will effectively result in you reimplementing parts of what's already in those headers (a.k.a. "reinventing the wheel").
I have two pieces of advice based on long experience with systems that did it badly :-)
The first is to not store date and time information as strings or integral values, especially when C++ has very good support for that in std::chrono. If you use the correct types, comparisons and manipulations become relatively simple.
Second, make sure you use UTC for all times. You should convert local times to UTC as soon as possible after getting them, and convert back to local as late as possible when presenting them. This will also greatly simplify comparisons.
By way of example, here's a complete program which show the simplicity(a) in action:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <chrono>
using std::chrono::system_clock;
using std::chrono::duration_cast;
namespace {
system_clock::time_point getTimePoint(std::string strTime) {
std::tm myTm = {};
std::stringstream ss(strTime.c_str());
ss >> std::get_time(&myTm, "%Y/%m/%d %H:%M");
return system_clock::from_time_t(std::mktime(&myTm));
}
void outputTime(const char *desc, system_clock::time_point &tp) {
std::time_t now = system_clock::to_time_t(tp);
std::cout << desc
<< std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M") << "\n";
}
}
int main() {
std::string startTime = "2019/04/15 10:30";
std::string endTime = "2019/04/16 09:30";
auto startTp = getTimePoint(startTime);
auto endTp = getTimePoint(endTime);
outputTime("Start time: ", startTp);
outputTime(" End time: ", endTp);
auto duration = duration_cast<std::chrono::minutes>(endTp - startTp);
std::cout << "\nThere are " << duration.count() << " minutes between "
<< startTime << " and " << endTime << "\n";
}
The output of that program is:
Start time: 2019-04-15 10:30
End time: 2019-04-16 09:30
There are 1380 minutes between 2019/04/15 10:30 and 2019/04/16 09:30
(a) Yes, the program may seem reasonably big but that's just because of the stuff making it a complete program. The getTimePoint and outputTime functions show how to do the conversion to and from time points, and the meat of the simplicity is the line containing duration_cast to get the number of minutes between the two time points.

How to insert a colon in between string as like date formats in c++?

I have string 20150410 121416 in c++.
I need to turn this into 20150410 12:14:16
How can i insert a colon to the string?
One can format date/times in C and C++ with strftime. There also exists a non-standard but common POSIX function called strptime one can use to parse times. One could use these to parse your date/time in your input format, and then format it back out in your desired format.
That is, assuming you didn't want to write the parsing code yourself.
If you have C++11, then you could use this free, open-source date/time library to help you do all this with strftime-like format strings. Such code could look like:
#include "tz.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace date;
std::string input = "20150410 121416";
std::stringstream stream{input};
stream.exceptions(std::ios::failbit);
sys_seconds tp;
parse(stream, "%Y%m%d %H%M%S", tp);
auto output = format("%Y%m%d %T", tp);
std::cout << output << '\n';
}
Output:
20150410 12:14:16
One advantage of using a date/time parsing/formatting library, as opposed to just treating these as generic strings, is that you can more easily alter the formatting, or manipulate the datetime during the format conversion (e.g. have it change timezones).
For example, next month the specification might change on you and now you're told that this is a timestamp representing local time in Moscow and you need to convert it to local time in London and output it in the form YYYY-MM-DD HH:MM:SS <UTC offset>. The above code hardly changes at all if you're using a good date/time library.
#include "tz.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace date;
std::string input = "20150410 121416";
std::stringstream stream{input};
stream.exceptions(std::ios::failbit);
local_seconds tp;
parse(stream, "%Y%m%d %H%M%S", tp);
auto moscow_time = make_zoned("Europe/Moscow", tp);
auto london_time = make_zoned("Europe/London", moscow_time);
auto output = format("%F %T %z", london_time);
std::cout << output << '\n';
}
2015-04-10 10:14:16 +0100
But if you started out just doing string manipulation, all of the sudden you've got a major task in front of you. Writing code that understands the semantics of the datetime "20150410 121416" is a significant leap above manipulating the characters of "20150410 121416" as a string.
<script type="text/javascript">
function formatTime(objFormField){
intFieldLength = objFormField.value.length;
if(intFieldLength==2 || intFieldLength == 2){
objFormField.value = objFormField.value + ":";
return false;
}
}
</script>
Enter time <input type="text" maxlength="5" minlength="5" onKeyPress="formatTime(this)"/>

How do I convert a string in seconds to time in C++

I have a string that stores the no of seconds since a process started. I need to convert this string with the no of seconds to time in C++. I need to subtract this time from the current time to get the time that this process started. I am confused and I do not know how to go about it. Please could someone help me out. I am a bit new to C++
Maybe you could try out Boost Time Library (http://www.boost.org/doc/libs/1_53_0/libs/timer/doc/index.html) or std::chrono if you're using newer compiler (as suggested below) and wish to stay within STL.
Something like that could work:
#include <chrono>
#include <string>
using namespace std::chrono;
std::string elapsed_time_in_s = "123456";
system_clock::time_point then = system_clock::now() -
std::chrono::seconds(std::stoll(elapsed_time_in_s));
time_t then_as_time_t = system_clock::to_time_t(then);
#include <sstream>
///
std::stringstream strs(seconds_string);
unsigned int tempTime=0;
if(!(strs >> tempTime))
//error
//calculate around with tempTime
if(!(strs << tempTime)
//error
if(!(strs >> seconds_string)
//error
//new string with the current time
You can use standard <time.h> routines (time, and gmtime or localtime).
For example:
void PrintProcessStartTimeAndDate(int numOfSeconds)
{
time_t rawtime;
struct tm* ptm;
time(&rawtime);
rawtime -= numOfSeconds;
ptm = gmtime(&rawtime); // or localtime(&rawtime);
printf("Process started at %.2d:%.2d:%.2d on %.2d/%.2d/%.2d\n",
ptm->tm_hour,ptm->tm_min,ptm->tm_sec,ptm->tm_mday,ptm->tm_mon+1,ptm->tm_year+1900);
}
Please note that gmtime and localtime routines are not thread-safe.
This fact is due to the pointer-to-static-structure that each one of them returns.

Convert SQLite Date Field to C++ Time_T

How Do I Convert A SQLite Date in the following format to a C++ Time_T Variable?
YYYY-MM-DD HH:MM:SS
You may wish to read this question, which discusses a few approaches. In particular, if you have access to Boost, you can use <boost/date_time/posix_time/posix_time.hpp> and create a boost::posix_time::ptime object from a string of the format in your question. (See the first answer in that question.)
Alternatively, you can use strptime().
Example:
#include <ctime>
#include <iostream>
std::size_t timestamp_to_seconds(const char* timestamp)
{
std::tm tm_struct;
strptime(timestamp, "%Y-%m-%d %H:%M:%S", &tm_struct);
// You can control daylight savings time if necessary.
tm_struct.tm_isdst = 1;
std::size_t t = std::mktime(&tm_struct);
return t;
}
int main()
{
std::cout << timestamp_to_seconds("2013-07-05 12:34:56") << std::endl;
return 0;
}
Running this example gives the following output:
$ ./a.out
1373042096
$ date -d "2013-07-05 12:34:56" +%s
1373042096
As you can see, it agrees with the date utility. (I assuming you are on a platform with access to strptime.) You may have to be careful when handling daylight savings or timezone info...I had to use tm_struct.tm_isdst = 1 to force recognition of daylight savings and get agreement with date.
time_t is a Unix timestamp (seconds since 1970-01-01), so you have to convert with strftime:
SELECT strftime('%s', '2013-07-05 12:34:56');
The result is a string, but you can read it as an integer value.