Displaying a date with a leading zero in the input C++ - c++

I am currently trying to create a header file that takes information from a user and displays information in a form.
For the most part, I have had no problem, however, I need the user to input their date of birth in the format MMDDYYYY, and then convert it to MM/DD/YYYY and display it in the form.
My problem is that if the user inputs the month '01-09', what displayed was nowhere near correct. I still need to display the month the exact way the user input it, so it has to be displayed as (i.e. 01/01/1967).
The variable for the patient's date of birth is called int patientDateOfBirth.
This data type cannot be changed, it has to be an int.
The method in the header file that I am using is as follows:
void PatientDemographicInformation::printPatientDateOfBirth( )
{
int userMonth, userDay, userYear;
String birthDate = String(itoa(patientDateOfBirth));
// Calculation to determine month, day, and year from the MMDDYYYY format.
userMonth = scanf ("%d", &userMonth);
// this was another method I used, however the leading zero messed it up.
// userMonth = patientDateOfBirth / 1000000;
userDay = patientDateOfBirth / 10000 % 100;
userYear = patientDateOfBirth % 10000;
cout << userMonth << "/";
cout << setfill('0') << setw(2) << userDay << "/";
cout << userYear;
}
Also, this is the first time I am using this forum, so if my formatting is off, please forgive me. I also have little experience with this language, so if the answer is simple, please go easy on me!
Thank you.
EDIT: I've just noticed that there is the variable String birthDate that is not used in the calculation. I was not sure if converting the int into a String would work, but I gave it a shot regardless, but it did not work and I forgot to remove that variable. If that could work, however, please let me know.
EDIT: Sorry if I wasn't as clear as I had hoped to be. I want the user to input a date of birth in the format MMDDYYYY and output it as MM/DD/YYYY, meaning I have to separate the month, day, and year into seperate variables and then put them into a cout statement.
The problem that I am having is if the user puts a 01 thru 09 as the month (i.e. 01141967),
When the method tries to do the calculation, I get some strange number in the output (i.e. 112230056/00004814/5599932) or the like. I am completely stumped by this dilemma. I've searched forever trying to find some kind of answer and I have tried several methods, all not working.

The impression you gave is that you have a patientDateOfBirth integer, in one the following formats: mmddyyyy OR mddyyyy, is that correct? If it is, the original
int month = patientDateOfBirth / 1000000;
int day = patientDateOfBirth / 10000 % 100;
int year = patientDateOfBirth % 10000;
should work ok, regardless of leading zeroes on some original input. An alternative would be using C++11's <chrono> classes or Boost's <boost/date_time.hpp> for your conversions...

Related

Using C++'s date library to read times

I am attempting to use Howard Hinnant's date library (https://github.com/HowardHinnant/date) to read user input into a datetime object. I would like to use this library since it's modern, and is to be included in C++20.
The program should be able to accept datetimes in ISO 8601 format (YYYY-MM-DDTHH:MM:SS+HHMM etc, eg 2020-07-07T18:30+0100) as well as simple datetimes in the form DD-MM HH:MM or HH:MM. In the second case, it should assume that the missing information is to be filled in with the current date/year (the timezone is to be dealt with later).
Here is my attempt at doing this.
using namespace date;
int main(int argc, char ** argv)
{
std::istringstream ss { argv[1] };
std::chrono::system_clock::time_point dt
{ std::chrono::system_clock::now() };
if ( date::from_stream(ss, "%F T %T %z", dt) ) {
std::cout << "Cond 1 entered\n";
}
else if ( ss.clear(), ss.seekg(0); date::from_stream(ss, "%d-%m %R", dt)) {
std::cout << "Cond 2 entered\n";
}
std::cout << dt << "\n";
}
For the first format, this works as expected:
./a.out 2020-06-07T18:30:00+0200
Cond 1 entered
2020-06-07 16:30:00.000000000
However, the second method returns something strange, depending on the compiler used. When compiled with GCC and -std=c++17/-std=c++2a:
./a.out "07-08 15:00"
Cond 2 entered
1754-04-06 13:43:41.128654848
EDIT 2: When compiled with LLVM and -std=c++2a:
./a.out "07-08 15:00"
Cond 2 entered
0000-08-07 15:00:00.000000
which is a little closer to what I was expecting.
I'd rather not have the behaviour dependent on the compiler used though!
I'm really stumped as to what's going on here, and I can't seem to make head or tail of the documentation.
How can I get date::from_stream to simply overwrite the time and date and leave everything else?
EDIT 1:
For clarity, I was (incorrectly) expecting that when the second condition is entered the current year is preserved, since the time_point object was initialised with the current year. E.g I hoped the second call to from_stream would leave the time_point object as 2020-08-07 15:00:33.803726000 in my second example.
See comments for further info.
EDIT 2:
Added results of trying with different compilers.
Good question!!!
You're not doing it quite right, and you found a bug in date.h! :-)
First, I've fixed the bug you hit here. The problem was that I had the wrong value for not_a_year in from_stream, and that bug has been hiding in there for years! Thanks much for helping me find it! To update just pull the tip of the master branch.
When your program is run with the fixed date.h with the argument "07-08 15:00", it enters neither condition and prints out the current time.
Explanation:
The semantics of from_stream(stream, fmt, x) is that if stream doesn't contain enough information to fully specify x using fmt, then stream.failbit gets set and x is not modified. And "07-08 15:00" doesn't fully specify a system_clock::time_point.
The bug in date.h was that date.h was failing to recognize that there wasn't enough information to fully specify the system_clock::time_point, and was writing deterministic garbage to it. And that garbage happened to produce two different values on LLVM/libc++ and gcc because of the different precisions of system_clock::time_point (microseconds vs nanoseconds).
With the bug fix, the parse fails outright, and thus doesn't write the garbage.
I'm sure your next question will be:
How do I make the second parse work?
int main(int argc, char ** argv)
{
std::istringstream ss { argv[1] };
auto dt = std::chrono::system_clock::now();
ss >> date::parse("%FT%T%z", dt);
if (!ss.fail())
{
std::cout << "Cond 1 entered\n";
}
else
{
ss.clear();
ss.seekg(0);
date::month_day md;
std::chrono::minutes hm;
ss >> date::parse("%d-%m", md) >> date::parse(" %R", hm);
if (!ss.fail())
{
std::cout << "Cond 2 entered\n";
using namespace date;
auto y = year_month_day{floor<days>(dt)}.year();
dt = sys_days{y/md} + hm;
}
}
std::cout << dt << "\n";
}
The first parse is just as you had it, except that I switched the use of parse for from_stream which is a little higher level API. This doesn't really matter for the first parse, but makes the second parse neater.
For the second parse you need to parse two items:
A month_day
A time of day
And then combine those two elements with the current year to produce the desired time_point.
Now each parse fully specifies the variable it is parsing from the stream.
The mistake you made originally was in imagining that there is a "year field" under the hood of system_clock::time_point. And actually this data structure is nothing but a count of microseconds or nanoseconds (or whatever) since 1970-01-01 00:00:00 UTC. So the second parse has to:
Parse the fields, and then
Deconstruct the time_point into fields to get the current year, and then
Put the fields back together again into a time_point.

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 do I take data from a CSV file, and parse the data into an INT between two commas?

First off, apologies for how unspecific this question may be, for it is my first time asking a question of StackOverflow.
I will get down to business, I am working on a project which reads a file (CSV specifically) and will then save certain data from there into an Int i will later mess with.
Essentially, my code is currently as followed:
if (!infile) {
cout << "You entered something that cannot be opened, please try again." << endl;
Continue = true;
}
else {
while (infile.good()) {
getline(infile, value, ','); // read a string until next comma
cout << string(value, 1, value.length() - 2); // display value removing the first and the last character from it
}
Continue = false;
}
}
So far, this reads the data and outputs lines that look like this:
2014-01-03,"2014","01","03","†","-12.8","","-31.0","","-21.9","","39.9","","0.0","","","M","","M","0.0","","","","","","<31",""
2014-01-04,"2014","01","04","†","-2.3","","-12.8","","-7.6","","25.6","","0.0","","","M","","M","2.9","","40","","18","","39",""
2014-01-05,"2014","01","05","†","-2.1","","-4.1","","-3.1","","21.1","","0.0","","","M","","M","16.2","","52","","8","","32",""
My information needed is between the 5th and 6th comma (it represents the average temperature for the day) and I somehow need to put the information between those two commas into some kind of int.
As well, between the 3rd and 4th comma is the day, which I will need later to calculate the average temperature for each month, so I need to figure that out as well.
Does anyone know the correct way to go about doing this? Unfortunately my knowledge of string parsing is to be desired.
Firstly, the values between the 5th and 6th commas are floating-point numbers - you should to convert it into either float or double.
Then,
If both
you always have a “.” as a separator in the floating-point numbers
C++17 or higher versions of the language is acceptable for you
use std::from_chars (https://en.cppreference.com/w/cpp/utility/from_chars)
If not, consider the following:
for signed integers - std::stoi/std::stol/std::stoll (https://en.cppreference.com/w/cpp/string/basic_string/stol)
and std::strtol/std::strtoll (https://en.cppreference.com/w/cpp/string/byte/strtol)
for unsigned integers - std::stoul/std::stoull (https://en.cppreference.com/w/cpp/string/basic_string/stoul) and std::strtoul/std::strtoull (https://en.cppreference.com/w/cpp/string/byte/strtoul)
for floating-point numbers - std::stof/std::stod/std::stold (https://en.cppreference.com/w/cpp/string/basic_string/stof), std::strtof/std::strtod/std::strtold (https://en.cppreference.com/w/cpp/string/byte/strtof) and for wide-character strings std::wcstof/std::wcstod/std::wcstold (https://en.cppreference.com/w/cpp/string/wide/wcstof)
If your compiler does not support the functions above, your only options are
atoi/atol (https://en.cppreference.com/w/cpp/string/byte/atoi)
and atof (https://en.cppreference.com/w/cpp/string/byte/atof), and sscanf (https://en.cppreference.com/w/cpp/io/c/fscanf).

Trying to extract only part of a string from a single line from a text file in c++

Okay this is the second time Ive looked for help for my program, I know I nearly got it but I cant figure it out. So right now Im trying to write a program that has the user input the date in the format dd/mm/yyyy and return it as month date, year. So 01/01/1990 becomes January 1st, 1990. I need to use a text file that has the names of the months beside their corresponding numbers. So the list of the text file looks like this:
01January
02February
03March
.. and so on.
So far I have this:
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
string thedate; //string to enter the date
string month; // this string will hold the month
ifstream myfile ("months.txt");
cout << "Please enter the date in the format dd/mm/yyyy, include the slashes: " << endl;
cin >> thedate;
month = thedate.substr( 3, 2 );
string newmonth;
if (myfile.is_open())
{
while ( myfile.good() )
{
getline (myfile,newmonth);
newmonth.find(month);
cout << newmonth << endl;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
So I have been able to extract the month from the user input, and store that as month, Im just not too sure how search the text file for that month, and return only the name of the month into a new string, only from that line. Right now if I enter 02/05/1990, it will output
05
05
05
05
05
.. for 12 lines.
I'm new to programming so any help is appreciated.
Also, I am only about 3 weeks into my programming course, and we haven't really learned functions, or arrays yet. So if you do have any help to offer, please avoid arrays and functions. I also understand it is easier to not read from a text file, but this is a requirement from my class to read it from the text file, so I need it.
Thanks.
The string::find function (that you already used) returns the position of the search string (-> month). You can now use the string::substr function to extract the part of the string you are looking for.
Hope that helps for a start.

Variable filename with ifstream and ofstream

I want to use the system date I have from the computer and use it as the name of the .txt file. Here's what I have so far:
void idle_time()
{
LASTINPUTINFO last_info;
last_info.cbSize = sizeof(LASTINPUTINFO);
int tickCount = 0;
int minutes = 0;
int count = 0;
SYSTEMTIME a;
while(true)
{
GetLastInputInfo(&last_info);
tickCount = GetTickCount();
int minutes = (tickCount - last_info.dwTime) / 60000;
count++;
string date;
date += a.wMonth;
date += "/";
date += a.wDay;
date += "/";
date += a.wYear;
if((minutes >= 1) && (count%3000==0))
{
//std::string filename = date;
//filename += ".txt";
ifstream in(string(date + ."txt").c_str());
float sum;
in >> sum;
sum++;
in.close();
ofstream out(string(date + ".txt").c_str());
out << sum;
out.flush();
out.close();
}
I'm sorry for the terrible indentation. This editor doesn't do it justice. But anyway, how would I use the date as the filename?
The date string you are using contains / characters which are used to separate directories in path. You simply need to replace them with another (not forbidden) character.
I'd also suggest you not to use m/d/Y date format for filenames. They do not sort well. Y-m-d is usually better because the files will be sorted from oldest to newest.
Edit: ah, and for my last statement to be true, you'd also need to pad month and day with zero to two digits, i.e. have something like 2011-08-05.
Ah, I see that the time appending is also done incorrectly. You can't append integers to strings like that. #hmjd already posted you one method of solving this; but I think it will be better to just use a dedicated time->string conversion method.
I'm not a Windows programmer, so I won't help you much with this SYSTEMTIME thing. You'll probably need to use GetTimeFormat(). But here's a simple example how to solve it with standard C/C++ strftime():
char date_buf[11];
time_t a = time(0);
strftime(date_buf, sizeof(buf), "%Y-%m-%d", gmtime(&t));
date += buf;
If you want the date in local time zone rather than UTC, use localtime() instead of gmtime().
Hope it helps someone. I believe GetTimeFormat() works similarly, so maybe this can guide you a bit.