Определение разницы между датами

Я пытаюсь найти способ для моей программы взять дату (например, 2 февраля 2003 года) и показать разницу между ними с другой датой (например, 2 апреля 2012 года), исключая високосные годы. До сих пор я только смог выяснить, находятся ли даты в том же месяце, просто вычитая "день". В этой программе я использую 2 набора целых чисел "месяц", "день" и "год". Я не знаю, куда идти дальше. Это совершенно необязательная часть моего задания, но я бы как получить представление о том, как заставить его работать. Мне кажется, что это хлопотно, но, может быть, есть простая математическая формула, о которой я не думаю?

Извините, у меня нет никакого существующего кода для этой части, потому что остальная часть задания просто имеет дело с тем, чтобы пользователь вводил даты, а затем добавлял и вычитал один день.

8 ответов


вот полный код для вычисления разницы дат в y/m / d.

предполагая, что до и С are дата типы, и что месяцы и дни начинаются с 1 (аналогично Qt):

static int increment[12] = { 1, -2, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1 };

int daysInc = 0;
if (to.day() - from.day() < 0)
{
    int month = to.month() - 2; // -1 from zero, -1 previous month.
    if (month < 0)
        month = 11; // Previous month is December.
    daysInc = increment[month];
    if ( (month == 1) && (to.year()%4 == 0) )
        daysInc++; // Increment days for leap year.
}

int total1 = from.year()*360 + from.month()*30 + from.day();
int total2 = to.year()*360 + to.month()*30 + to.day();
int diff = total2 - total1;
int years = diff/360;
int months = (diff - years*360)/30;
int days = diff - years*360 - months*30 + daysInc;

// Extra calculation when we can pass one month instead of 30 days.
if (from.day() == 1 && to.day() == 31) {
    months--;
    days = 30;
}

Я пробовал этот алгоритм, и он работает хорошо. Дайте мне знать, если у вас есть проблемы с использованием/ее понимания.


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

#include <ctime>

// Make a tm structure representing this date
std::tm make_tm(int year, int month, int day)
{
    std::tm tm = {0};
    tm.tm_year = year - 1900; // years count from 1900
    tm.tm_mon = month - 1;    // months count from January=0
    tm.tm_mday = day;         // days count from 1
    return tm;
}

// Structures representing the two dates
std::tm tm1 = make_tm(2012,4,2);    // April 2nd, 2012
std::tm tm2 = make_tm(2003,2,2);    // February 2nd, 2003

// Arithmetic time values.
// On a posix system, these are seconds since 1970-01-01 00:00:00 UTC
std::time_t time1 = std::mktime(&tm1);
std::time_t time2 = std::mktime(&tm2);

// Divide by the number of seconds in a day
const int seconds_per_day = 60*60*24;
std::time_t difference = (time1 - time2) / seconds_per_day;    

// To be fully portable, we shouldn't assume that these are Unix time;
// instead, we should use "difftime" to give the difference in seconds:
double portable_difference = std::difftime(time1, time2) / seconds_per_day;

Использование Boost.Дата_время немного менее странно:

#include "boost/date_time/gregorian/gregorian_types.hpp"

using namespace boost::gregorian;
date date1(2012, Apr, 2);
date date2(2003, Feb, 2);
long difference = (date1 - date2).days();

мне кажется, что это хлопотно, но, может быть, есть простая математическая формула, о которой я не думаю?

это действительно хлопот, но есть формула, если вы хотите сделайте расчет самостоятельно.


раз вы ищете математические формулы , она поможет вам найти решение вашей проблемы. Пусть Y будет годом, M-месяцем, D-днем. Сделайте этот расчет для обеих дат.

Total = Y * 365 + M * 30 + D, затем найдите разницу между 2 итогами соответствующих дат.

умножая 30 на значение M, вы должны указать количество дней в этом месяце. Вы можете сделать это с помощью #define value или if loop. Аналогично вы можете сделать для прыжка год тоже путем умножения 366 на Y .

надеюсь, это поможет u....


новый ответ на старый вопрос:

chrono - Совместимые Низкоуровневые Алгоритмы Даты

имеет формулы для преобразования {год, месяц, день} тройной в последовательное количество дней и обратно. Вы можете использовать его для расчета количества дней между двумя датами, как это:

std::cout << days_from_civil(2012, 4, 2) - days_from_civil(2003, 2, 2) << '\n';

выходы:

3347

бумага-это руководство, а не библиотека. Она использует C++14 для демонстрации формул. Каждый рецепт поставляется с подробное описание и вывод, которые вам нужно прочитать, только если вы заботитесь о том, как работает формула.

Формулы очень эффективны, и действительны над весьма большим рядом. Например, используя 32-битную арифметику, + / - 5 миллионов лет (более чем достаточно).

количество последовательных дней-это количество дней с (или до отрицательных значений) нового 1970 года, что делает формулы совместимыми с Время Unix и все известные реализации std::chrono::system_clock.

на days_from_civil алгоритм не является новым, и он должен выглядеть очень похожим на другие алгоритмы для выполнения того же самого. Но идти в другую сторону, от количества дней назад до тройки {год, месяц, день} сложнее. Это формула, задокументированная civil_from_days и я не видел других формулировок, которые так компактны, как этот.

в документе приведен пример использования showing типичные вычисления, std::chrono совместимость, и обширная тесты демонстрируя правильность в течение + / - 1 миллиона лет (используя Григорианскому календарю).

все формулы и программное обеспечение находятся в открытом доступе.


Я не уверен, на какой платформе вы работаете? Windows, Linux? Но давайте притворимся, что вы хотели бы иметь независимое от платформы решение, а langugage является стандартным c++.

Если вы можете использовать библиотеки вы можете использовать импульс::библиотека Дата_время (http://www.boost.org/doc/libs/1_49_0/doc/html/date_time.html)

Если вы не можете использовать библиотеки для решения вашего задания, вам нужно будет найти общую простую основу. Может быть, вы могли бы преобразовать все даты в секунды, или дни вычитают их, а затем снова преобразуют обратно в данные. Вычитание дней или месяцев в целые числа не поможет, так как это приведет к неправильным результатам, если вы не учитываете остальное. Надеюсь, это поможет.

Как указал dbrank0. :)


есть другой путь...

  • учитывая две даты, возьмите год более ранней даты как отчетный год.
  • затем вычислить нет. дней между каждой из двух данных дат и этой 1/1 /
  • держите отдельную функцию, которая сообщает количество дней, прошедших до определенного месяца.
  • абсолютная разница этих двух нет. дней даст разницу между две даты.
  • кроме того, не забудьте рассмотреть високосные годы!

код:

#‎include‬<stdio.h>
#include<math.h>
typedef struct
{
    int d, m, y;
} Date;
int isLeap (int y)
{
    return (y % 4 == 0) && ( y % 100 != 0) || (y % 400 == 0);
}
int diff (Date d1, Date d2)                         //logic here!
{
    int dd1 = 0, dd2 = 0, y, yref;                  //dd1 and dd2 store the <i>no. of days</i> between d1, d2 and the reference year
    yref = (d1.y < d2.y)? d1.y: d2.y;               //that <b>reference year</b>
    for (y = yref; y < d1.y; y++)
        if (isLeap(y))                              //check if there is any leap year between the reference year and d1's year (exclusive)
            dd1++;
    if (isLeap(d1.y) && d1.m > 2) dd1++;                //add another day if the date is past a leap year's February
    dd1 += daysTill(d1.m) + d1.d + (d1.y - yref) * 365;     //sum up all the tiny bits (days)
    for (y = yref; y < d2.y; y++)                       //repeat for d2
        if(isLeap(y))
            dd2++;
    if (isLeap(y) && d2.m > 2) dd2++;
    dd2 += daysTill(d2.m) + d2.d + (d2.y - yref) * 365;
    return abs(dd2 - dd1);                          //return the absolute difference between the two <i>no. of days elapsed past the reference year</i>
}
int daysTill (int month)                            //some logic here too!!
{
    int days = 0;
    switch (month)
    {
        case 1: days = 0;
        break;
        case 2: days = 31;
        break;
        case 3: days = 59;
        break;
        case 4: days = 90;      //number of days elapsed before April in a non-leap year
        break;
        case 5: days = 120;
        break;
        case 6: days = 151;
        break;
        case 7: days = 181;
        break;
        case 8: days = 212;
        break;
        case 9: days = 243;
        break;
        case 10:days = 273;
        break;
        case 11:days = 304;
        break;
        case 12:days = 334;
        break;
    }
    return days;
}
main()
{
    int t;          //no. of test cases
    Date d1, d2;    //d1 is the first date, d2 is the second one! obvious, duh!?
    scanf ("%d", &t);
    while (t--)
    {
        scanf ("%d %d %d", &d1.d, &d1.m, &d1.y);
        scanf ("%d %d %d", &d2.d, &d2.m, &d2.y);
        printf ("%d\n", diff(d1, d2));
    }
}

Стандартный Ввод:

1
23 9 1960
11 3 2015

Стандартный Вывод:

19892

код в действии:https://ideone.com/RrADFR

лучшие алгоритмы, оптимизации и правки приветствуются!


Если вам нужно сделать это самостоятельно, то один из способов сделать это довольно легко путем преобразования даты в Юлианский День. Вы получаете формулы по этой ссылке, и с момента преобразования вы работаете только с поплавками, где каждый день составляет 1 единицу.


вы должны посмотреть DateTime класса.

и ссылка на MSDN для синтаксиса C++.