Определение разницы между датами
Я пытаюсь найти способ для моей программы взять дату (например, 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++.