String to Date with exceptions c++

I have a task to make static method getDateFromString in class Date that receives the date as a string as the only parameter and returns it as Date. I also need to check whether the date is in the correct format using UnparseableDateException (with which I also am having troubles) exception class before converting it to Date. Here is my code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//UnparseableDateException.h

class UnparseableDateException : public exception {
    private:
        string message;
    public:
        UnparseableDateException() : message ("Unparseable date: 21.5a.2020"){}
        const char* what() const noexcept override{
        return message.c_str();
        }

    };


//Date.h

class Date {
private:
    int day;
    int month;
    int year;
public:
    Date(int day, int month, int year);

    int getDay() const;

    int getMonth() const;

    int getYear() const;

    string toString() const;

    static string getDateFromString(string a);
};

//Date.cpp
#include "Date.h"

int Date::getDay() const {
    return day;
}

int Date::getMonth() const {
    return month;
}

int Date::getYear() const {
    return year;
}

Date::Date(int day, int month, int year) {
this->day = day;
this->month = month;
this->year = year;
}

string Date::toString() const {
    stringstream ss;
    ss << "day: " << day << " month: " << month << " year: " << year;
    return ss.str();
}

string Date::getDateFromString(string a) {
 // ???
}
Last edited on
To start, you have to define what the requirement for a valid date and an invalid date string is. Then, write code that fulfills that requirement.

Is "21.5.2020" (Day.Month.Year) the format you're saying is valid?
What deviation from this is allowed?
Is "21.05.2020" valid? What about "21/5/2020"?
What about dates that are "parseable", but in valid, like "29/2/2019"? Should that also throw an exception?

Anyway, the first part is just parsing the date in some expected format.
So if your expected format is "M.D.Y", then I suggest using a combination of stringstreams with '.' being the delimter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// Example program
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <stdexcept>

using namespace std;

struct Date {
    int day;
    int month;
    int year;
};

bool is_number(string str)
{
    for (size_t i = 0; i < str.length(); i++)
    {
        if (!isdigit(str[i]))
        {
            return false;   
        }
    }
    return true;
}

Date parse(string str)
{
    istringstream iss(str);
    
    string day_str;
    getline(iss, day_str, '.');
    
    string month_str;
    getline(iss, month_str, '.');
    
    string year_str; 
    getline(iss, year_str);
    
    if (!is_number(day_str))
    {
        throw exception();   
    }
    int day = atoi(day_str.c_str());
    if (!day)
    {
        throw exception();
    }
    
    if (!is_number(month_str))
    {
        throw exception();   
    }
    int month = atoi(month_str.c_str());
    if (!month)
    {
        throw exception();
    }
    
    if (!is_number(year_str))
    {
        throw exception();   
    }
    int year = atoi(year_str.c_str());
    if (!year)
    {
        throw exception();
    }
     
    return Date{day, month, year};
}

int main()
{
    try
    {
        Date date = parse("21.5a.2020");
        cout << date.day << " " << date.month << " " << date.year << '\n';
    }
    catch (...)
    {
        cout << "Invalid date\n";   
    }

}

(My implementation could be reduced by using an array int[3] and some for loops)
Last edited on
Just do the reverse of your toString function, and throw the exception if you can’t read one of the pieces of information.
No deviation is allowed from that format. It should be Day . (dot) month (with no 0 if single digit) . (dot) year
See this, there is a validation list, if date is bad exception is thrown, otherwise date is printed to console, see code comments for more info:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <exception>
using namespace std;

vector<int> Date::getDateFromString(string str)
{
        // holds extracted date
	std::vector<int> date;

        // holds validation list
	std::vector<char> valid = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };

        // sample to work with (day, month of year)
	std::istringstream ss(str);

        // ignore dots
	while (std::getline(ss, str, '.'))
	{
                // temporary
                string temp = str;

                // doing validation here, accepting only numbers
		for (const auto& ref : str)
			if (std::find(valid.begin(), valid.end(), ref) == valid.end())
				throw std::invalid_argument("date is not valid");
			else if (ref == '0' && str.size() == 2)
			{
                                // remove zero if found
				std::size_t pos = temp.find('0');
				temp.erase(pos, pos);
			}

                // if OK convert to integer and store day, month and year
		int num = std::atoi(str.c_str());

		date.push_back(num);
	}

	return date;
}

// TEST CASE
int main() try
{
	// try to screw up this date to see exception
	std::string date("21.5.2020");
	auto result = Date::getDateFromString(date);

        // show result, integers (day, month and year)
	for (const auto& ref : result)
	{
		std::cout << ref << std::endl;
	}
}
catch (std::invalid_argument& ex)
{
	// If invalid input exception is trhown and programs aborts
	std::cout << ex.what() << std::endl;
}
Last edited on
I have edited my post, can you try again please.

What compiler are you using? what do you use to compile code?

don't forget the headers from my post!
Last edited on
I am using CLion, but now it works fine i forgot <algorithm>...
I have only one question: In main when i include class "Date.h" i 've got error like this:
error: 'vector' does not name a type; did you mean 'perror'?
This error shows even when i only add #include "Date.h" and main is empty, and when i delete "Date.h" from main.cpp i am not having errors, what could possibly be the problem here?
Put this line on top of your Date.h
#include <vector>

also inside your header function getDateFromString should be using be std::vector not vector

example:
std::vector<int> Date::getDateFromString(std::string str);

Alternatively copy all header includes into your headers to be 100% sure.

btw. is this for your assignment?
Last edited on
Okay, it worked finally :D thanks, and yes it's for assignment
OK, I'm glad it did, but don't be silly, your teacher will know you didn't write this ;)
I don't use this code, I just want to see how it works, so I can learn it and do it myself.
that's good to hear!
Topic archived. No new replies allowed.