Я делаю проект, который должен отслеживать даты, связанные с книгами. Я храню даты в виде строк. Мне нужно распечатать все книги, которые были опубликованы после указанной даты.
Ниже приведен цикл, аналогичный тому, что я делаю в своем коде, который повторяет проблему непоследовательного сравнения значений двух дат.
#include <time.h>
#include <stdio.h>
#include <string>
#include <ctime>
#include <vector>
int main()
{
std::string comp_against = "11/1995";
std::vector<std::string> dates = {"11/1995", "10/1990", "03/2004", "2/1992", "11/1995"};
for(auto it = dates.begin(); it != dates.end(); ++it)
{
std::string date = *it;
struct tm t1;
struct tm t2;
// parse the dates with mm/YYYY format
strptime(comp_against.c_str(), "%m/%Y", &t1);
strptime(date.c_str(), "%m/%Y", &t2);
std::time_t s1 = mktime(&t1);
std::time_t s2 = mktime(&t2);
printf("%s > %s: %s\n", date.c_str(), comp_against.c_str(), (s2 > s1 ? "true" : "false"));
}
return 0;
}
Вывод на мой компьютер:
11/1995 > 11/1995: false <- these two are different
10/1990 > 11/1995: false |
03/2004 > 11/1995: true |
2/1992 > 11/1995: false |
11/1995 > 11/1995: true <- these two are different
Когда я запускаю свой реальный код, проблема меняется. Когда дата «11/1995» сравнивается с самой собой в начале цикла на первой итерации, s2>s1
оценивает true
скорее, чем false
как вывод выше, и второе сравнение оценивает false
,
РЕДАКТИРОВАТЬ:
Если я сделаю сравнение с difftime, я получу ту же проблему. добавлять printf("%s > %s: %s\n", date.c_str(), comp_against.c_str(), (difftime(s2, s1) > 0.0 ? "true" : "false"));
а также printf("\n");
после printf
в приведенном выше коде, и вы получите ниже вывод.
11/1995 > 11/1995: false <- different
11/1995 > 11/1995: false |
10/1990 > 11/1995: false |
10/1990 > 11/1995: false |
03/2004 > 11/1995: true |
03/2004 > 11/1995: true |
2/1992 > 11/1995: false |
2/1992 > 11/1995: false |
11/1995 > 11/1995: true |
11/1995 > 11/1995: true <- different
Ваш strptime
извлечения не заселяют все в struct tm
конструкции, которые вы им поставляете; они только заполняют элементы, необходимые для производства запрошенных вами форматных данных.
Измени свой struct tm
декларации к этому:
struct tm t1{}; // value initialize members
struct tm t2{}; // here too.
при условии, что вы используете C ++ 11-совместимый набор инструментов. При этом получается:
11/1995 > 11/1995: false
10/1990 > 11/1995: false
03/2004 > 11/1995: true
2/1992 > 11/1995: false
11/1995 > 11/1995: false
И если вам интересно, как:
printf("%ld %ld : %s > %s: %s\n", s1, s2, date.c_str(),
comp_against.c_str(), (s2 > s1 ? "true" : "false"));
который произвел это без инициализации значения вашего tm
Структуры:
815126400 815126400 : 11/1995 > 11/1995: false
817804800 657360000 : 10/1990 > 11/1995: false
815212800 1080720000 : 03/2004 > 11/1995: true
815212800 699523200 : 2/1992 > 11/1995: false
815212800 815299200 : 11/1995 > 11/1995: true
и производит это с инициализацией:
815126400 815126400 : 11/1995 > 11/1995: false
815126400 654681600 : 10/1990 > 11/1995: false
815126400 1078041600 : 03/2004 > 11/1995: true
815126400 696844800 : 2/1992 > 11/1995: false
815126400 815126400 : 11/1995 > 11/1995: false
В принципе, эта функция не инициализирует tm, но сохраняет указанные значения. Это означает, что tm должен быть инициализирован перед вызовом.
Решение:
struct tm t1 = {}; // same for t2 ...
Используя это бесплатная, с открытым исходным кодом, только заголовок, библиотека дат C ++ 11/14, вот способ сделать ваш код более простым и менее подверженным ошибкам:
#include "date.h"#include <iostream>
#include <vector>
int main()
{
using namespace date::literals;
auto comp_against = 1995_y/11;
std::vector<date::year_month> dates = {1995_y/11, 1990_y/10, 2004_y/03,
1992_y/2, 1995_y/11};
std::cout << std::boolalpha;
for(auto it = dates.begin(); it != dates.end(); ++it)
std::cout << *it << " > " << comp_against << ": "<< (*it > comp_against) << '\n';
}
Выход:
1995/Nov > 1995/Nov: false
1990/Oct > 1995/Nov: false
2004/Mar > 1995/Nov: true
1992/Feb > 1995/Nov: false
1995/Nov > 1995/Nov: false