Using Preprocessor DATE dynamically - c++

I'm trying to use __DATE__ in C++Builder, and I need to use it dynamically. For example, if a user click on a button, the label containing __DATE__ will update following the system date.
I did that for now:
label1->Text = "Data: " __DATE__;
This is in a function to set the date, called DateTime(). For the button I already did the click event, but I need the DateTime() to run dynamically.

__DATE__ is a compile-time constant. It is the date on which the .cpp file is compiled. This is not what you want in this situation.
C++Builder's RTL has a Sysutils::Date() function that you can use instead, eg:
#include <System.SysUtils.hpp>
label1->Text = _T("Data: ") + Date().DateString();
Date() returns a TDateTime representing the current system date (if you want to include time as well, use Sysutils::Now() instead). Its DateString() method formats the TDateTime into a String using the user's locale settings. If you want to format the TDateTime yourself, you can use its FormatString() method for that, eg:
#include <System.SysUtils.hpp>
label1->Text = _T("Data: ") + Date().FormatString(_T("yyyy-mm-dd"));
or:
label1->Text = Date().FormatString(_T("'Data: 'yyyy-mm-dd"));
If you want a more standard C++ solution, look at the std::time() and std:::strftime() functions, eg:
#include <ctime>
std::time_t now_c = std::time(nullptr);
std::tm now_tm = *std::localtime(&now_c);
char buffer[11] = {};
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d", &now_tm);
label1->Text = _T("Data: ") + String(buffer);
or:
label1->Text = String().sprintf(_T("Data: %s"), buffer);
Or, look at the <chrono> library introduced in C++11, such as std::chrono::system_clock, eg:
#include <chrono>
#include <ctime>
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::tm now_tm = *std::localtime(&now_c);
char buffer[11] = {};
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d", &now_tm);
label1->Text = _T("Data: ") + String(buffer);
or:
label1->Text = String().sprintf(_T("Data: %s"), buffer);
Alternatively:
#include <chrono>
#include <ctime>
#include <sstream>
#include <iomanip>
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::tm now_tm = *std::localtime(&now_c);
std::wostringstream oss;
oss << L"Data: " << std::put_time(&now_tm, L"%Y-%m-%d");
label1->Text = oss.str().c_str();

The __DATE__ symbol is a pre-processor macro, hence it is only defined at compile time.
That means that the actual value of __DATE__ will not change during the execution of your program. It will be the time of your compilation. Forever the same value in the executable that you have just compiled.
If you need date string that reflects the current system clock/date, then you will need to use some function that queries the system for the current, as time(). Definitely not a compile-time-pre-processor macro string as __DATE__. See other ctime functions to assist you in formatting the desired string.
Finally, about building the string: you will need to compose strings at runtime much as sprintf does. Your construction "Data: " __DATE__ is just valid because you are again concatenating string as compilation time (it is the compiler pre-processor the one doing the concatenation, no your program). Here you can read about this capability of the C pre-processor. Also,here is described that this is a C99 standard behaviour, but cannot tell if it was not defined in an earlier C standard.

Related

How do I write a message timestamp to a log file?

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.

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)"/>

Can't Create Dynamic Folder Name

In C++ I want to create a dynamic folder each time I run my program.
#include <direct.h> // mkdir
#include <iostream> // std
#include <iomanip> // put_time
int main(){
time_t rawtime;
struct tm * timeinfo;
char buffer[40];
time(&rawtime);
timeinfo = localtime(&rawtime);
//strftime(buffer, sizeof(buffer), "%d-%m-%Y %I:%M:%S", timeinfo);
strftime(buffer, sizeof(buffer), "%d_%m_%Y_%I_%M_%S", timeinfo);
std::string path = "C:/example/";
path.append(std::string(buffer));
mkdir(path.c_str());
//system("pause");
return 0;
}
I want to create a folder named like "Example/03_03_2016_20_22_26", but the code above will not create the folder I want.
If I remove the path.append(std::string(buffer)); line, it will create the folder named example in my C directory.
However I want a folder named according to the complete date and time.
Where am I wrong or what am I missing?
I use this code for a similar purpose in my project (SAVE_DIR is a macro definition):
#include <time.h>
#include <iomanip>
#include <sstream>
std::ostringstream pathstr; // a convenient way to construct strings
std::time_t now = std::time(nullptr); // get the current time
// insert the required parts into the stream
pathstr << SAVE_DIR
<< std::put_time(std::localtime(&now), "%Y_%m_%d_%H_%M_%S") << ".png";
std::string path = pathstr.str(); // and the result as std::str
Output:
/home/user/prog/render/rt/saves/2016_03_03_23_10_50.png
This has the benefit of being pure C++, though it may look a bit clumsy, depending on your taste.
As for what your code may fail, I'd watch the string values in a debugger first, and then save the return value of mkdir() and check it against the specifications: POSIX mkdir().
I guess the issue is in the slash '/'.
On Windows better use the backslash.
Try
std::string path="C:\\example\\"

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.

c++ to_string error with date

I am trying to write a function that returns the date as a string. I went about this like so:
string date() // includes not listed for sake of space, using namespace std
{
tm timeStruct;
int currentMonth = timeStruct.tm_mon + 1;
int currentDay = timeStruct.tm_mday;
int currentYear = timeStruct.tm_year - 100;
string currentDate = to_string(currentMonth) + "/" + to_string(currentDay) + "/" + to_string(currentYear);
return currentDate;
}
this is giving four compile time errors.
1 of these:
to_string was not declared in this scope
and 3 of these:
Function to_string could not be resolved
one for each use of to_string.
According to everywhere else on the internet, this code should work. Can someone please shed some light on the subject?
As has been mentioned in the comments, what you're trying to use requires C++11. This means both a compiler that supports C++11 (E.g. GCC 4.7+), AND possibly manually enabling C++11 (E.g. flag -std=c++11), so check both of those if you believe it should be working for you.
If you're stuck with a compiler that does not support C++11, you can use the following to achieve what you want, with regular C++:
string date()
{
tm timeStruct;
int currentMonth = timeStruct.tm_mon + 1;
int currentDay = timeStruct.tm_mday;
int currentYear = timeStruct.tm_year - 100;
char currentDate[30];
sprintf(currentDate, "%02d/%02d/%d", currentMonth, currentDay, currentYear);
return currentDate; // it will automatically be converted to string
}
Note that for the Day and Month parameters, I used %02d to force it to display at least 2 digits, so 5/1 will actually be represented as 05/01. If you don't want that, you can just use %d instead, which will behave like your original to_string. (I'm not sure what format you're using for currentYear, but you'll probably also want to use either %02d or %04d for that parameter)
std::to_string is part of C++11 and is in the <string> header. The following code works with g++ 4.7, as well as recent versions of clang and VC++. If compiling a file with these contents does not work for you, you are either invoking the compiler incorrectly for C++11 or using a compiler version with insufficient support for C++11.
#include <string>
int main() {
int i;
auto s = std::to_string(i);
}
However there is a better way to print dates in C++11. Here's a program that prints the current date (in ISO 8601 format).
#include <ctime> // time, time_t, tm, localtime
#include <iomanip> // put_time
#include <iostream> // cout
#include <sstream> // stringstream
#include <stdexcept> // runtime_error
#include <string> // string
std::string date() {
static constexpr char const *date_format = "%Y-%m-%d"; // ISO 8601 format
auto t = std::time(nullptr);
if (static_cast<std::time_t>(-1) == t) {
throw std::runtime_error{"std::time failed"};
}
auto *cal = std::localtime(&t);
if (nullptr == cal) {
throw std::runtime_error{"std::localetime failed"};
}
std::stringstream ss;
ss << std::put_time(cal, date_format);
return ss.str();
}
int main() { std::cout << date() << '\n'; }
Unfortunately gcc 4.8 appears to lack put_time (and of course VC++ currently lacks constexpr and universal initializers, but that is easily worked around. VC++ has put_time).