C++ check if a date is valid - c++

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

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);

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

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";

Related

Unable to convert string with seconds from epoch to date_time

I have a string containing the seconds from the epoch, how do i convert this string to a format
as such -
YEAR-MONTH-DAY HH:MM:SS
Here MONTH should display the month number and DAY gives the day number. Also the time needs to be in 24 hour format.
For example :
2019-06-26 11:14:25
I have tried using strptime but havent been successful in doing so, could someone help me in what I am doing wrong.
This is what i have tried so far
int main()
{
string timee = "12341234534";
const char *ptr = timee.c_str();
struct tm tim;
strptime(ptr, "%S", &tim);
time_t abcd = mktime(&tim);
cout<<abcd;
return 0;
}
Found this code snippet on another stackoverflow link
How to convert a string variable containing time to time_t type in c++?
Your question is a little confusing, but I think I figured out what you want...
If the time is in a time_t compatible format, then just read it directly into a time_t variable, and convert it through std::localtime so you can output it in the wanted format using std::put_time.
Something like
std::time_t time;
std::cin >> time;
std::cout << std::put_time(std::localtime(&time), "%F %T") << '\n';

Test if string represents "yyyy-mm-dd"

I am working on a program that takes two command line arguments. Both arguments should be dates of the form yyyy-mm-dd. Since other folks will be using this program and it will be requesting from mysql, I want to make sure that the command line arguments are valid. My original thought was to loop over each element of the incoming string and perform some kind of test on it. The '-' would be easy to check but I'm not so sure how to handle the digits, and to distinguish them between ints and chars. Also, I need the first date to be "less than or equal to" the second but I'm pretty sure I can handle that.
If you can use boost library you could simple do it like this:
string date("2015-11-12");
string format("%Y-%m-%d");
date parsedDate = parser.parse_date(date, format, svp);
You can read more about this here.
If you want a pure C++ solution you can try using
struct tm tm;
std::string s("2015-11-123");
if (strptime(s.c_str(), "%Y-%m-%d", &tm))
std::cout << "Validate date" << std::endl;
else
std::cout << "Invalid date" << std::endl;
Additionally you can do a simple check to see if the date is valid, and is not for example 2351-20-35. A simple solution would be:
bool isleapyear(unsigned short year){
return (!(year%4) && (year%100) || !(year%400));
}
//1 valid, 0 invalid
bool valid_date(unsigned short year,unsigned short month,unsigned short day){
unsigned short monthlen[]={31,28,31,30,31,30,31,31,30,31,30,31};
if (!year || !month || !day || month>12)
return 0;
if (isleapyear(year) && month==2)
monthlen[1]++;
if (day>monthlen[month-1])
return 0;
return 1;
}
Source: http://www.cplusplus.com/forum/general/3094/

how to get boost::posix_time::ptime from formatted string

I have a formated string like "2012-03-28T08:00:00".
i want to get year, month(in string format),date,hour, min ,sec and day (in string format).
can any one suggest me the easiest way to do it in boost.
thanks
If the existing from_string() methods do not suit your needs then you can use a time input facet that allows you to customise the format from which the string is parsed.
In your case you can use the ISO extended format string so you can use the following code to parse your strings:
boost::posix_time::time_input_facet *tif = new boost::posix_time::time_input_facet;
tif->set_iso_extended_format();
std::istringstream iss("2012-03-28T08:00:00");
iss.imbue(std::locale(std::locale::classic(), tif));
iss >> abs_time;
std::cout << abs_time << std::endl;
Without using facets;
ptime dateTime = boost::date_time::parse_delimited_time<ptime>(string, 'T');
The two from*_string functions have limits on what formats are converted.
Does not accept 'T': time_from_string(s).
Does not accept '-': from_iso_string(s).
Roundtripping ISO 8601 date/time in boost;
std::string date = to_iso_extended_string(dateTime);

Convert string to boost::gregorian::greg_month

In the Boost date time library, is there a utility function for converting month short strings (e.g. Jan, Feb, Mar, Apr) to boost::gregorian::greg_month type? The documentation for the library isn't great and I can't see anything in the headers.
A hacky work around could be:
#include <iostream>
#include <boost/date_time/gregorian/gregorian.hpp>
int main(void)
{
auto ptr = boost::gregorian::greg_month::get_month_map_ptr();
if (ptr)
{
auto it = ptr->begin();
for(; it != ptr->end(); ++it)
{
std::cout << it->first << " " << it->second << '\n';
}
}
}
This map contains mapping between all the short/long names and the short necessary to create a greg_month instance. Just need to create a little wrapper around it...
per Graeme's discovery, there is a convenience function which wraps this already boost::date_time::month_str_to_ushort<>
Yes, there are boost date time facets that can be used to create locales and put into streams.
Beware though that if you are going to print or parse a large number of dates and times you do not create the facet and locale for each one you parse.
Look here for documentation on inputting dates. Some of their examples use short month names, which appears to have %b as its format specifier

Getting numeric timezone in specified format

I would like to print the current time as 2011-08-18 10:11:12 -07:00. I developed a code snippet as below,
#include <iostream>
using namespace std;
void time_to_string(time_t clock,const char *fmtstr )
{
char buf[256];
if (strftime(buf, 256, fmtstr, localtime(&clock)) == 0)
buf[0] = 0;
cout << buf << endl;
}
int main()
{
time_to_string(time(NULL), "%Y-%m-%d %H%M%S %z");
}
I am able to display the time as 2011-08-18 10:11:12 -0700 but not as 2011-08-18 10:11:12 -07:00. Using "%Y-%m-%d %H%M%S %:z" produces 2011-08-18 10:11:12 %:z.
How can i accomplish the above task in C/C++.
You would have to manually split the string which is formated by %z as +hhmm or -hhmm. %z has a fixed format. Look at the description of strftime.
Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ), or by no characters if no timezone is determinable.
Build one string with date and time. Build a second string with the offset from UTC with %z, insert the : in the second string. Concatenate first and second string.
It tries to interpret %: and it doesn't match a format specifier, so it prints it out as is. But you probably knew that already =)
In your time_to_string function, I would manually insert the ':' into the buffer before displaying it.
The syntax you tried don't exist.
What I would do is calling the function twice : once with "%Y-%m-%d %H%M%S ", and once with "%z", manually add the : in the second string, and then concatenate the two.
To insert the :, you could do an ugly buffer manipulation :
buf2[5]=buf2[4];
buf2[4]=buf2[3];
buf2[3]=':';
strcat(buf,buf2);
Note that the layout isn't likely to change for this specific data, so it's not so ugly.
0r if you really like overkill, a regexp. But you'll need an external library.
You can manually add the ':' at the end, modifying the result string. e.g.,
buf[26]='\0';
buf[25]=buf[24];
buf[24]=buf[23];
buf[23]=':';
I may be overlooking a better solution.