• B правой части каждого сообщения есть стрелки и . Не стесняйтесь оценивать ответы. Чтобы автору вопроса закрыть свой тикет, надо выбрать лучший ответ. Просто нажмите значок в правой части сообщения.

число дней между датами

  • Автор темы Автор темы Olej
  • Дата начала Дата начала
  • Теги Теги
    c++ c/c++
O

Olej

Хорошая задача: найти число дней между 2-мя датами ... заданными строкой, скажем, в формате: "dd.mm.yyyy" (или каком хотите другом).

1-е решение - самое худшее! (которое немедленно кидаются писать пЫАнЭры) - это тут же начать изобретать свой календарь, в меру своего (всегда ошибочного) понимания как календарь устроен: 30/31 дней, 28/29 и високосные годы и т.п.

Правильные (и без ошибок в ответе!) решения на C или C++ должны бы использовать системные функции даты/времени, POSIX API в случае C, например.

А как бы вы решили эту задачу?
(не заглядывая заранее в ответы ниже)
 
  • Нравится
Реакции: Сергей Попов
2-е решение, используя POSIX API службы дата/время, язык C...
(не утверждаю, что это оптимальное решение, это одно из возможных, но оно иллюстрирует очень важное правило: не надо изобретать свой календарь!):
Код:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>

time_t normalize( struct tm *date ) {
   time_t t = mktime( date );
   *date = *localtime( &t );
   return t;
}

int main( int argc, char **argv ) {
   if( argc != 3 ) printf( "число параметров\n" ), exit( 1 );
   struct tm date[ 2 ] = { {}, {} };
   time_t t[ 2 ];
   for( int i = 0; i < 2; i++ ) {
      int num = 0;
      char *token = strtok( argv[ i + 1 ], "." );
      while( token != 0 ) {
         if( 0 == atoi( token ) ) printf( "формат даты\n" ), exit( 1 );
         switch( num++ ) {
            case 0: date[ i ].tm_mday = atoi( token ); break;  
            case 1: date[ i ].tm_mon = atoi( token ) - 1; break;
            case 2: date[ i ].tm_year = atoi( token ) - 1900; break;
            default: printf( "формат даты\n" ), exit( 1 );
         }
         token = strtok( NULL, "." );
      }
      if( num != 3 ) printf( "формат даты\n" ), exit( 1 );
      t[ i ] = normalize( date + i );
      printf( "%s дата:\t%s", i ? "конечная" : "начальная", asctime( &date[ i ] ) );
   }
   if( t[ 1 ] < t[ 0 ] ) printf( "последовательность дат\n" ), exit( 1 );
   unsigned day = 0;
   while( date[ 0 ].tm_year < date[ 1 ].tm_year ) {
      struct tm last = {      
         .tm_mday = 31, .tm_mon = 11, .tm_year = date[ 0 ].tm_year
      };
      normalize( &last );
      day += last.tm_yday - date[ 0 ].tm_yday + 1;
      date[ 0 ].tm_mday = 1; date[ 0 ].tm_mon = 0; date[ 0 ].tm_year = date[ 0 ].tm_year + 1;
      normalize( date );
   } // пока годы различаются
   day += date[ 1 ].tm_yday - date[ 0 ].tm_yday;
   printf( "между ними дней: %d\n", day );
   return 0;
}
А теперь внимание! Результаты:
Код:
[olej@dell time]$ ./difd 01.01.2015 01.01.2016
начальная дата: Thu Jan  1 00:00:00 2015
конечная дата:  Fri Jan  1 00:00:00 2016
между ними дней: 365

[olej@dell time]$ ./difd 01.01.2016 01.01.2017
начальная дата: Fri Jan  1 00:00:00 2016
конечная дата:  Sun Jan  1 00:00:00 2017
между ними дней: 366

[olej@dell time]$ ./difd 01.01.2000 01.01.2001
начальная дата: Sat Jan  1 00:00:00 2000
конечная дата:  Mon Jan  1 00:00:00 2001
между ними дней: 366

[olej@dell time]$ ./difd 01.01.1900 01.01.1901
начальная дата: Mon Jan  1 00:00:00 1900
конечная дата:  Tue Jan  1 00:00:00 1901
между ними дней: 365
Как вам такая разница дней в году? ;)
 
  • Нравится
Реакции: Сергей Попов
Одно из лучших упражнений в коде: напишите код решающий задачу X так, чтобы код был самый короткий. Моя бы воля, я бы заставлял студентов так решать задачи. ;)

И всё та же задача, что выше сформулирована...
Язык C++ (на этот раз).
Но при C++ есть такой огромный набор библиотек как Boost (стандартная библиотека C++, как её сейчас называют, позаимствовала свою большую и лучшую часть именно из Boost: потоки, контейнерные клвссы STL и др.).
Вот и воспользуемся библиотекой Boost:
Код:
#include <iostream>
#include <locale>
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace std;

int main() {
    cin.imbue( locale( cin.getloc(), new boost::gregorian::date_input_facet( "%d.%m.%Y" ) ) );
    boost::gregorian::date d1, d2;
    cin >> d1 >> d2;
    if( d1 > d2 )
        swap( d1, d2 );
    cout << d2 - d1 << endl;
}
Вот и всё ! o_O
Код:
[olej@dell boost]$ ./difd
01.01.2016
01.01.2017
366

[olej@dell boost]$ ./difd
01.01.2015
01.01.2016
365

[olej@dell boost]$ ./difd
01.01.2000
01.01.2001
366

[olej@dell boost]$ ./difd
01.01.1900
01.01.1901
365
 
Последнее редактирование:
  • Нравится
Реакции: Сергей Попов
Одно из лучших упражнений в коде: напишите код решающий задачу X так, чтобы код был самый короткий. Моя бы воля, я бы заставлял студентов так решать задачи. ;)

И всё та же задача, что выше сформулирована...
Язык C++ (на этот раз).
Но при C++ есть такой огромный набор библиотек как Boost (стандартная библиотека C++, как её сейчас называют, позаимствовала свою большую и лучшую часть именно из Boost: потоки, контейнерные клвссы STL и др.).
Вот и воспользуемся библиотекой Boost:
Код:
#include <iostream>
#include <locale>
#include <boost/date_time/gregorian/gregorian.hpp>
using namespace std;

int main() {
    cin.imbue( locale( cin.getloc(), new boost::gregorian::date_input_facet( "%d.%m.%Y" ) ) );
    boost::gregorian::date d1, d2;
    cin >> d1 >> d2;
    if( d1 > d2 )
        swap( d1, d2 );
    cout << d2 - d1 << endl;
}
Вот и всё ! o_O
Код:
[olej@dell boost]$ ./difd
01.01.2016
01.01.2017
366

[olej@dell boost]$ ./difd
01.01.2015
01.01.2016
365

[olej@dell boost]$ ./difd
01.01.2000
01.01.2001
366

[olej@dell boost]$ ./difd
01.01.1900
01.01.1901
365
Это че за пергамент?! DateDiff чем не угодил, в одну строчку решается задача.
 
DateDiff чем не угодил, в одну строчку решается задача.
DateDiff - это с какого языка будет? ... Visual Basic?

P.S. Название целого раздела форума "C/C++/C#" уже не отчётливо видится ... двоится? А до Нового Года ещё столько времени... :eek:
 
Последнее редактирование модератором:
DateDiff - это с какого языка будет? ... Visual Basic?
Господ вынь-даунов просят не беспокоиться ... не вмешиваться во взрослые разговоры. :(

P.S. Название целого раздела форума "C/C++/C#" уже не отчётливо видится ... двоится? А до Нового Года ещё столько времени... :eek:
окай на шарпе, в одну строку.
upload_2016-12-31_20-26-11.png
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!