确定日期之间的差异

时间:2012-04-03 05:28:07

标签: c++ visual-studio visual-studio-2010 visual-c++

我试图找出一个方法让我的程序采取约会(如2003年2月2日),并显示两者之间的差异与另一个日期(如2012年4月2日),不包括闰年。到目前为止,我只能通过减去" day"来确定日期是否在同一个月。在这个程序中,我使用2套"月","日"和"年"整数。从这里开始,我几乎不知所措。这是我任务中完全可选的一部分,但我想知道如何让它发挥作用。这对我来说似乎很麻烦,但也许这是一个我没想过的简单的数学公式?

抱歉,我没有此部分的任何预先存在的代码,因为其余的任务只涉及让用户输入日期然后添加和减去一天。

9 个答案:

答案 0 :(得分:14)

仅使用标准库,您可以将适度疯狂的日期结构转换为自任意零点以来的秒数;然后减去并转换成天:

#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.Date_Time有点不太奇怪:

#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();
  

这对我来说似乎很麻烦,但也许有一个简单的数学公式我不会考虑?

这确实很麻烦,但如果你想自己做计算,那就有一个formula

答案 1 :(得分:7)

由于您正在寻找数学公式,它将帮助您找到问题的解决方案。设Y为年,M为月,D为日。对这两个日期进行此计算。

总计= Y * 365 + M * 30 + D,然后找出相应日期的2个总数之间的差异。

在将30乘以M值时,您必须给出该月的天数。您可以使用#define值或if循环执行此操作。同样地,你也可以通过将366与Y相乘来实现闰年。

希望这会对你有所帮助....

答案 2 :(得分:6)

旧问题的新答案:

chrono-Compatible Low-Level Date Algorithms

具有将{年,月,日}三元组转换为天数和后续数的公式。您可以使用它来计算两个日期之间的天数,如下所示:

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

输出:

3347

该论文是一本操作手册,而非图书馆。它使用C ++ 14来演示公式。每个公式都附有详细的描述和推导,如果您关心公式如何运作,您只需要阅读。

公式非常有效,并且在极大范围内有效。例如,使用32位算术,+ / - 5百万年(绰绰有余)。

序列日计数是自1970年新年以来(或负值之前)的天数,使公式与Unix Time以及std::chrono::system_clock的所有已知实现兼容。

days_from_civil算法并不新颖,它应该与其他算法非常相似,可以做同样的事情。但另一方面,从几天回到{年,月,日}三倍是更棘手的。这是civil_from_days记录的公式,我没有看到其他公式与此一样紧凑。

该论文包含显示typical computationsstd::chrono interoperability和广泛unit tests的示例用法,展示了超过+/- 1百万年的正确性(使用proleptic Gregorian calendar)。

所有公式和软件都属于公共领域。

答案 3 :(得分:5)

以下是以y / m / d计算日期差异的完整代码。

假设来自日期类型,并且这些月份和日期从 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;
}

我尝试了这个算法,它运行正常。如果您在使用/理解它时遇到麻烦,请告诉我。

答案 4 :(得分:2)

我不确定你在哪个平台? Windows,Linux?但是,让我们假装您希望拥有一个独立于平台的解决方案,并且该语言是标准的C ++。

如果您可以使用库,您可以使用Boost :: Date_Time库(http://www.boost.org/doc/libs/1_49_0/doc/html/date_time.html)

如果你不能使用库来解决你的任务,你需要找到一个共同的简单基础。也许您可以将所有日期转换为秒,或将天数减去它们,然后再将其转换回数据。将整数天或月作为整数进行减法将无济于事,因为除非您不考虑其余部分,否则会导致错误的结果。 希望有所帮助。

像dbrank0指出的那样。 :)

答案 5 :(得分:2)

还有另一种方式...

  • 鉴于两个日期,请将较早日期的年份作为参考年度
  • 然后计算否。两个给定日期之间的日期以及1/1 /&lt;那年&gt;
  • 保留一个单独的函数,告知特定月份之前的天数。
  • 这两个的绝对差异没有。天数将给出两个给定日期之间的差异。
  • 另外,不要忘记考虑闰年

代码:

#‎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

欢迎更好的算法,优化和编辑!

答案 6 :(得分:1)

如果您需要自己完成,那么通过将日期转换为Julian Day,可以轻松实现这一目标。您可以在该链接获得公式,并且从转换开始,您只能使用浮点数,其中每天为1个单位。

答案 7 :(得分:0)

您应该查看DateTime课程。

C ++语法的msdn reference

答案 8 :(得分:0)

我做了类似的程序,但它只计算一年或几年的天数

PS 我只学了两个月的 C++ 编程

    #include<iostream>

    int calculateDaysInYears(int intYear, int endYear);
    int checkYear(int intYear);
    int checkMonth(int i, int intYear);

    int getUserData()
{
    int dayOrMonthOrYear;
    std::cin >> dayOrMonthOrYear;
    return dayOrMonthOrYear;
}
    int calculateMonthInYears(int initialMonth, int endMonth, int initialYear)
{
    //Подсчет дней начальной даты для варианта с несколькими годами
    int x(0);

    initialMonth++;

    for (int i = initialMonth; i <= endMonth; i++)
        x += checkMonth(i, initialYear);

    return x;
}
    int calculateMonth(int startMonth, int endMonth, int initialYear)
{
    //Формула для подсчета кол-вa дней промежуточных месяцев
    //Расчет в пределах года
    
    startMonth++;

    int x(0);

    for (int i = startMonth; i < endMonth; i++)

        x += checkMonth(i, initialYear);

    return x;
}
    int calculateMonthForEndYear(int endMonth, int endYear)
{
    //Подсчет дней в конечном году
    int x(0);

    //Декремент кол-ва конечных месяцев для компенсации дней последнего месяца
    --endMonth;

    for (int i = 1; i <= endMonth; i++)
        x += checkMonth(i, endYear);

    return x;
}
    int checkMonth(int i, int intYear)
{
        if (i == 1 || i == 3 || i == 5 || i == 7 || i == 8 || i == 10 || i == 12)
            return 31;
        else 
            if (i == 2)
            {
                //Если год високосный, то делится на 4 и 400 без остатка, а на 100 с остатком
                if ((intYear % 4 == 0) && (intYear % 100 != 0 ) || (intYear % 400 == 0))
                    return 29;                                                  
                else
                    return 28;
            }
        else
            return 30;

}
    int calculateAmountOfDays(int initialDay, int initialMonth, int initialYear)
{
    //Подсчет дней до конца стартового месяца
    int month = checkMonth(initialMonth, initialYear);
    int days = month - initialDay;
    return days;
}
    int allDays(int initilDays, int endDays, int midleMonth)
{
    int totalDays;
    
    //Подсчет всех дней от начала до конца
    totalDays = midleMonth + initilDays + endDays;
    return totalDays;
}
    int checkYear(int intYear)
{
    if ((intYear % 4 == 0) && (intYear % 100 != 0) || (intYear % 400 == 0))
        return 366;//Високосный год
    else
        return 365;//Невисокосный год
}
    int calculateDaysInYears(int intYear, int endYear)
{
    //Начальное кол-во дней. Необходимо для запуска счетчика
    int amountDays(0);

    //Инкремент начального года для компенсации кол-ва дней промежуточных годов
    intYear++;

    for (int i = intYear; i < endYear; i++)
        amountDays += checkYear(i);

    return amountDays;
}
    int main()
{
    int initialDay;
    int initialMonth;
    int initialYear;
    int endDay;
    int endMonth;
    int endYear;

    std::cout << "Hello! I'm your calendar calculator."            << std::endl <<
                 "Here some rules: "                               << std::endl << 
                 "you should enter a data like(d.m.y): 23.8.2020." << std::endl <<
                 "Also you can ask me to calculate for couple years or in border of one year. Good luck! " << std::endl;

    std::cout << "" << std::endl;

    //Начальная дата
    std::cout << "Enter an initial day: ";
    initialDay = getUserData();

    std::cout << "Enter an initial month: ";
    initialMonth = getUserData();

    std::cout << "Enter an initial year: ";
    initialYear = getUserData();

    std::cout << "" << std::endl;//Пропуск строки

    //Конечная дата
    std::cout << "Enter an end day: ";
    endDay = getUserData();

    std::cout << "Enter an end month: ";
    endMonth = getUserData();

    std::cout << "Enter an end year: ";
    endYear = getUserData();

    //Проверка кол-ва годов
    if ((endYear - initialYear) >= 1)
    {
        //Подсчет дней до конца начального года
        int daysToTheEndOfStartYear = calculateMonthInYears(initialMonth, 12, initialYear) + calculateAmountOfDays(initialDay, initialMonth, initialYear);

        //Подсчет дней до конца конечного месяца
        int daysToTheEndOfEndYear = calculateMonthForEndYear(endMonth, endYear) + endDay;

        //Подсчет дней между годами
        int whalDays = calculateDaysInYears(initialYear, endYear);

        //Подсчет конечной цыфры
        int allDay = whalDays + daysToTheEndOfEndYear + daysToTheEndOfStartYear;

        //Вывод в консоль
        std::cout << allDay;
    }
    else
    {
        //Дни месяцев между начальным и конечным месяцами
        int daysInMonths = calculateMonth(initialMonth, endMonth, initialYear);

        //Подсчет дней до конца начального месяца
        int daysInFirstMonth = calculateAmountOfDays(initialDay, initialMonth, initialYear);

        //Подсчет конечной цыфры
        int allDay = daysInMonths + daysInFirstMonth + endDay;

        //Вывод в консоль
        std::cout << allDay;
    }
    return 0;
}