C++ check if a date is valid
Asked Answered
C

6

11

is there any function to check if a given date is valid or not? I don't want to write anything from scratch.

e.g. 32/10/2012 is not valid and 10/10/2010 is valid

Carycaryatid answered 24/2, 2012 at 19:19 Comment(2)
Where does this value originate? What is done with it?Thelma
it's the input. I just wanna check if it's valid or not.Carycaryatid
P
8

If your string is always in that format the easiest thing to do would be to split the string into its three components, populate a tm structure and pass it to mktime(). If it returns -1 then it's not a valid date.

You could also use Boost.Date_Time to parse it:

string inp("10/10/2010");
string format("%d/%m/%Y");
date d;
d = parser.parse_date(inp, format, svp);
Prowess answered 24/2, 2012 at 19:23 Comment(4)
What svp and parser are?Ious
mktime will normalize a date. For example, if the day is negative, it will wrap back to the previous month and adjust the day and month members accordingly.Bultman
mktime: The values in time are permitted to be outside their normal rangesJudaism
please add full header and typedef to your code.Atropine
B
4

The boost date time class should be able to handle what you require. See http://www.boost.org/doc/libs/release/doc/html/date_time.html

Besot answered 24/2, 2012 at 19:23 Comment(3)
Or the current version, boost.org/doc/libs/1_48_0/doc/html/date_time.htmlBrucite
Ahh. Yes, let me edit my post to reflect that. Thank you Fred.Besot
Or what I'm sure is the current release link. :) Thank you Vlad.Besot
J
3

If the format of the date is constant and you don't want to use boost, you can always use strptime, defined in the ctime header:

const char date1[] = "32/10/2012";
const char date2[] = "10/10/2012";
struct tm tm;

if (!strptime(date1, "%d/%m/%Y", &tm)) std::cout << "date1 isn't valid\n";
if (!strptime(date2, "%d/%m/%Y", &tm)) std::cout << "date2 isn't valid\n";
Jedjedd answered 24/2, 2012 at 19:44 Comment(2)
Bear in mind strptime() is a non-standard extension that is not available on all systems (including Windows).Prowess
@spencercw: Indeed. There are, however, open source implementations for most systems, including Windows. Also, it's a POSIX's standard. :)Jedjedd
W
2

I faced a similar problem recently, but unfortunately didn't figure out boost, and mktime didn't solve my problem. So I decided to manually throw a check for date-time. Hope, it will help someone

 bool isDateAndtimeValid( std::vector<int> time ) {
    if( time[1]> 12) return false; //month
    if( time[2]> 31 ) return false; //day
    if( time[2] == 31 and ( time[1] == 4 or time[1] == 6 or time[1] == 9 or time[1] == 11 ) ) return false; //30 days in Apr, Jun, Sen, Nov
    if( time[1] == 2) {
      if( time[2] > 29 ) return false;
      if( time[2] == 29 and ( ( time[0]%100 )%4 != 0) ) return false;
    } //Feb
    if( time[3] > 23) return false; //hours
    if( time[4] > 59 ) return false; //min
    if( time[5] > 59) return false; //sec
    return true;
    }
Wormseed answered 17/3, 2023 at 14:57 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Shainashaine
When this question was asked and answered, there was no std::get_time. But if you're running into the same problem today, that's what you would want to use.Duffel
F
0

You can do it just like this, (in this example I used - as date separator you can replace - with \ and test it).

I just split the given date into three parts Y-D-M then store them into tm struct, in order to convert it to Unix Time.

Here is the tm struct content:

struct tm {
   int tm_sec;         /* seconds,  range 0 to 59          */
   int tm_min;         /* minutes, range 0 to 59           */
   int tm_hour;        /* hours, range 0 to 23             */
   int tm_mday;        /* day of the month, range 1 to 31  */
   int tm_mon;         /* month, range 0 to 11             */
   int tm_year;        /* The number of years since 1900   */
   int tm_wday;        /* day of the week, range 0 to 6    */
   int tm_yday;        /* day in the year, range 0 to 365  */
   int tm_isdst;       /* daylight saving time             */   
};

for example you entered this date 2024-02-31 and then stored it into tm struct, when you will call mktime() it will fix the bad range you entered, since there is no 31st day in February, then you can compare the old tm and the new tm and check if their values match, if not then the date is not valid.

bool checkDateFormat(const std::string& dateString) {

    char dash;
    std::stringstream ss(dateString);

    struct tm date;
    struct tm newDate;

    ss >> date.tm_year >> dash >> date.tm_mon >> dash >> date.tm_mday;
    date.tm_year -= 1900; date.tm_mon -= 1;
    date.tm_hour = 1;            // Hour
    date.tm_min = 0;             // Minute
    date.tm_sec = 0;             // Second    

    newDate = date;
    time_t unix_time = mktime(&newDate);
    if (
        date.tm_year == newDate.tm_year &&
        date.tm_mon == newDate.tm_mon   &&
        date.tm_mday == newDate.tm_mday
    )   
        return true; 
    return false;
}

int main() {

    if (checkDateFormat("2024-02-31") == true)
        std::cout << "true" << std::endl;
    else
        std::cout << "false" << std::endl;
}

you can also print their dates in a readable format like the following:

char buffer[1337];
strftime(buffer, sizeof(buffer), "%c", &date );
std::cout << "date entered: " + std::string(buffer) << std::endl;
strftime(buffer, sizeof(buffer), "%c", &newDate );
std::cout << "date after rounding with mktime: " + std::string(buffer) << std::endl;

insert this code part just after this line

time_t unix_time = mktime(&newDate);

here is an example of what will you get:

date entered: Sun Feb 31 01:00:00 2024
date after rounding with mktime: Sat Mar  2 02:00:00 2024

as you can see 31 Feb became 2 Mar, since 2024/Feb has just 29 days it got rounded.

Forjudge answered 29/3 at 8:28 Comment(1)
thanks for @Prowess for his answer, I got to come with this answerForjudge
S
0

C++20 now makes this easier:

#include <chrono>
#include <iostream>
#include <string>
#include <sstream>

bool
is_valid_date(std::string date)
{
    std::istringstream in{std::move(date)};
    std::chrono::year_month_day ymd;
    in >> std::chrono::parse("%d/%m/%Y", ymd);
    return !in.fail();
}

int
main()
{
    std::cout << is_valid_date("32/10/2012") << '\n';
    std::cout << is_valid_date("10/10/2010") << '\n';
}

Output:

0
1

Demo.

MSVC has this. Coming soon with gcc-14. LLVM is in the implementation stage (as I write this).

Saucier answered 29/3 at 15:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.