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).
Related
I tried strftime, which has %z and %Z, but these are outputs like +0800 and PST. I'd like to get the longer name like America/Los_Angeles. Is there a function call to do this?
There is not a standard way to do this until C++20, and even then only the latest MSVC has implemented it to date (gcc is getting close).
In C++20 there is a type std::chrono::time_zone which has a member function called name() which will return a string such as "America/Los_Angeles".
It might be used like this:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace std::chrono;
zoned_time local_now{"America/Los_Angeles", system_clock::now()};
cout << local_now << " " << local_now.get_time_zone()->name() << '\n';
}
Which just output for me:
2022-12-31 07:34:41.482431 PST America/Los_Angeles
Or if your computer's local time zone is currently set to "America/Los_Angeles", then the zoned_time construction could look like this instead:
zoned_time local_now{current_zone(), system_clock::now()};
If all you want is the time zone name, and not the current time, this can be further simplified to just:
cout << current_zone()->name() << '\n';
Prior to C++20 the only way I'm aware of to get functionality like this is to use my free, open-source C++20 chrono preview library which will work with C++11/14/17.
One way — I must admit, a decidedly imperfect way — is to read the symbolic link /etc/localtime:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define LOCALTIME "/etc/localtime"
int main()
{
char buf[100];
int r = readlink(LOCALTIME, buf, sizeof(buf)-1);
if(r < 0) {
fprintf(stderr, "can't read link %s: %s\n", LOCALTIME, strerror(errno));
exit(1);
}
buf[r] = '\0';
char *name = buf;
char *p1 = strstr(buf, "zone");
if(p1 != NULL) {
char *p2;
p2 = strstr(p1 + 1, "zone");
if(p2 != NULL) p1 = p2;
p2 = strchr(p1, '/');
if(p2 != NULL)
name = p2 + 1;
}
printf("%s\n", name);
}
This will work on most Unix-like systems, including Linux and MacOS. It will not work on Windows, which AFAIK does not use the IANA tz database at all. It will not work on systems where /etc/localtime is a file, rather than a symbolic link to one of the zoneinfo files.
If /etc/localtime is a file, there is no good way to determine which zone name it represents. I believe you would have to compare it to all of the files underneath /usr/share/zoneinfo, looking for matching contents.
I'm not sure what magic technique Howard uses in his C++ solution.
(But I mean no disrespect with that word "magic".)
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.
I'm new to C++. I'm trying to write a small program that will take a .txt file from my desktop, sort it in a folder and rename it to current date.
My idea is in combining three strings, first string is a direction to the main directory where I want to move the file, second string is the name of the month in my native language and the third string is the string that represents the date in dd-mm.txt format.
#include <iostream>
#include <filesystem>
#include <ctime>
using namespace std;
int main() {
int result;
std::time_t t = std::time(0);
std::tm* now = std::localtime(&t);
char date_string[100];
strftime(date_string, 50, "\\%e-%m.txt", now);
string mnths[12] = { "Januar", "Februar","Mart","April","Maj","Jun","Jul","Avgust","Septembar","Oktobar","Novembar","Decembar" };
char strt[] = "C:\\Users\\B\\Desktop\\New.txt";
char fnsh[] = "C:\\Users\\B\\Desktop\\Journal\\2020\\"+ mnths[date_string[month]]+ date_string;
result = rename(strt, fnsh);
if (result == 0)
puts("File successfully renamed");
else
perror("Error renaming file");
return 0;
};
For the second string, in case of April for example, I want to get the fourth value in the mnths array. I've tried a mishmash of solutions looking up online but now I'm lost and need help. Most notable error is "Expression must have integral or unscoped enum type" and I've googled it but I still can't understand completely how it relates to my problem and how I can fix it. Thank you.
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)"/>
In C++ what is the simplest way to add one day to a date in this format:
"20090629-05:57:43"
Probably using Boost 1.36 - Boost::date, Boost::posix_date or any other boost or std library functionality, I'm not interested in other libraries.
So far I came up with:
format the string (split date and time parts as string op) to be able to initialize boost::gregorian::date, date expects format like:
"2009-06-29 05:57:43"
I have
"20090629-05:57:43"
add one day (boost date_duration stuff)
convert back to_simple_string and append the time part (string operation)
Is there any easier/niftier way to do this?
I am looking at run time efficiency.
Example code for the above steps:
using namespace boost::gregorian;
string orig("20090629-05:57:43");
string dday(orig.substr(0,8));
string dtime(orig.substr(8));
date d(from_undelimited_string(dday));
date_duration dd(1);
d += dd;
string result(to_iso_string(d) + dtime);
result:
20090630-05:57:43
That's pretty close to the simplest method I know of. About the only way to simplify it further would be using facets for the I/O stuff, to eliminate the need for string manipulation:
#include <iostream>
#include <sstream>
#include <locale>
#include <boost/date_time.hpp>
using namespace boost::local_time;
int main() {
std::stringstream ss;
local_time_facet* output_facet = new local_time_facet();
local_time_input_facet* input_facet = new local_time_input_facet();
ss.imbue(std::locale(std::locale::classic(), output_facet));
ss.imbue(std::locale(ss.getloc(), input_facet));
local_date_time ldt(not_a_date_time);
input_facet->format("%Y%m%d-%H:%M:%S");
ss.str("20090629-05:57:43");
ss >> ldt;
output_facet->format("%Y%m%d-%H:%M:%S");
ss.str(std::string());
ss << ldt;
std::cout << ss.str() << std::endl;
}
That's longer, and arguably harder to understand, though. I haven't tried to prove it, but I suspect it would be about equal runtime-efficiency that way.