Как узнать, осталась ли моя структура struct tm в недопустимом состоянии?

Это вопрос о недопустимом вводе, не недопустимом форматировании. Например, учитывая следующий код:

tm bar;

foo >> get_time(&bar, "%Y-%m-%d");

cout >> bar.tm_year >> bar.tm_mon >> bar.tm_mday >> endl;

Это нормально, если я определяю: stringstream foo("2001-02-28 non-leap year"); И имеет явную ошибку, если у меня недопустимый формат, например: stringstream foo("bad format 2001-02-28 non-leap year");

Но я не знаю, как определить, был ли мой ввод недействительным, например:

stringstream foo("2001-02-30 non-leap year");

В этом случае bar можно читать так, как будто все в порядке. Есть ли что-то, что я могу прослушать, что предупредит меня о том, что ввод недействителен?


person Jonathan Mee    schedule 27.03.2015    source источник
comment
Полагаю, if (foo >> get_time(...)) {/*use bar*/}   -  person chris    schedule 28.03.2015
comment
@chris Нет, это эквивалентно if(foo.good()), для которого устанавливается значение false, только если форматирование недействительно, а не если ввод недействителен. Обычно вы можете протестировать облачный компилятор Visual Studio, но они не работают уже целый день...   -  person Jonathan Mee    schedule 28.03.2015


Ответы (2)


Поскольку mktime пытается также интерпретировать значения, выходящие за пределы диапазона (т. е. для 2001-02-30 будет интерпретироваться как 2001-03-01), вы можете сделать mktime, за которым следует localtime, если вы получите другие значения, это означает, что оригинальные не годились.

person Matteo Italia    schedule 27.03.2015
comment
Выполнение преобразования дважды кажется болезненно дорогим способом добиться этого, но я полагаю, что это сработает. - person Jonathan Mee; 30.03.2015

Как упоминается в ответе Matteo Italia, помимо написания собственного григорианского валидатора, ваша единственная надежная двойная проверка mktime. tm, полученные с помощью get_time, не могут быть проверены, так как поля могут быть заполнены или не заполнены. Рассмотрим следующие 2 недопустимых примера:

Делаем так: istringstream("2001-02-30") >> get_time(&bar, "%Y-%m-%d"); приводит к результату, который изменится при тщательном выполнении mktime:

bar.tm_mday : 30
bar.tm_mon : 1
bar.tm_year : 100

При этом: istringstream("2001-13-30") >> get_time(&bar, "%Y-%m-%d"); приводит к результату, который не изменится при прогоне через mktime:

bar.tm_mday : 13
bar.tm_mon : 0
bar.tm_year : 100

Чтобы все недопустимые даты были изменены с помощью mktime, нам нужно прочитать дату без использования get_time:

int year;
int month;
int day;
istringstream foo("2000-13-30");

foo >> year >> ws;
foo.ignore();
foo >> month >> ws;
foo.ignore();
foo >> day;

tm bar = { 0, 0, 0, day, month - 1, year - 1900 };

На этом этапе любая ошибка в bar может быть исправлена ​​с помощью mktime, поэтому нашим фактическим шагом проверки будет проверка возврата, отличного от time_t(-1), и сравнение измененного bar назад с исходными значениями: if(time_t(-1) != mktime(&bar) && bar.tm_mday == day && bar.tm_mon == month - 1 && bar.tm_year == year - 1900)< /strong> если это условие верно, то вход в bar был верным.

В заключение, можно проверить tm без написания григорианского валидатора, но невозможно проверить tm, который был прочитан get_time.

person Jonathan Mee    schedule 02.04.2015