计算下个月开始日的算法

时间:2013-05-02 20:02:37

标签: c++ time calendar

我正在写一个简单的日历类。我正在尝试重载operator++以使用它将日历移动到下个月。但是,我找到下个月开始日的算法并不完全正确。

calendar calendar::operator ++(int)
{
   int hold;
   calendar cal = *this;

   month++;
   if (month > December)
   {
      month = January;
      year++;
      if (year == 0)
         year++;
   }
   previousStartDay = startDay;
   startDay = nextStartDay;
   nextStartDay = findNextStartDay();
   return cal;
}

int calendar::findNextStartDay() const
{
   int monthLength,
       day = startDay;

   monthLength = findMonthLength(false);
   monthLength -= 28;
   day += monthLength;
   if (day > Saturday)
      day -= Saturday;
   return day;
}

1月被定义为0,12月是11,星期日是0,星期六是6. startDay,previousStartDay,nextStartDay,month和year都是私有类变量

当我在2013年测试时,日期是正确的,直到3月。在这一点上,它将下一个开始日定为星期二而不是星期一。

我也试过这个:

int calendar::findNextStartDay() const
{
   int monthLength,
       day = startDay;

   monthLength = findMonthLength(false);
   monthLength -= 28;
   day -= monthLength;
   if (day < Sunday)
      day += Saturday;
   return day;
}

然而,它也给出了相同的结果。

修改

我正在考虑闰年。以下是我findMonthLength()的代码,以确定它是否存在。

if ((!(year % 4) && (year % 100)) || !(year % 400))
   monthLength = 29;
else
   monthLength = 28;

4 个答案:

答案 0 :(得分:3)

问题分析

假设我们在三月,你有正确的开始日(星期五,5)。

您的findNextStartDay算法会发现monthlength等于3(31-28),然后一天将是2(8 - 6),即星期二(2)而不是星期一(1)。 ..

让我们通过运行算法(第一版findNextStartDay)来了解这是错误的原因:

1月:31-28 = 3,日= 2(星期二)+ 3 = 5(星期五),这是2月的正确开始日期。

2月:28 - 28 = 0,日= 5(星期五)+ 0 = 5(星期五),这是3月的正确开始日期。

3月:31-28 = 3,日= 5(星期五)+ 3 - 6(星期六)= 2(星期二),这是错误的4月开始日期。

错误说明

问题在于,当你将星期六减去溢出的结果(超过星期六)时,你将离开计数一天(即:你减去一天比你想要的少一天)。

想想你最终得到day == 7的情况。你想要星期天(比周六多一点 - 循环增加),然后你必须删除7而不是6,否则你将获得星期一!

错误是循环增量:在正确的算法1中,超过6(即7)必须返回0,2超过6(即8)必须返回1,依此类推。

在你的算法1中,超过6(即7)会回到1,遗漏穷人0(星期日),并且每次你在这种情况下结束时,每周的一天都会消失。

如果你减去Saturday + 1,那么在#34;星期几天溢出&#34;的情况下,你会得到下个月的正确日期。

错误修复

简而言之,请更改此行:

day -= Saturday;

day -= (Saturday + 1);

但是请考虑将代码复习到更简洁的算法版本中!

一个小技巧是使用模运算符进行循环加法:

day = ((day + monthlength) % (Saturday + 1))

答案 1 :(得分:1)

boost为您提供了几个不错的examples。在这里,我根据示例中的一个实现了boost::gregorian。此代码需要年,月和打印日期和下个月第一天的星期几:

#include <cstdlib>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
#include <stdio.h>

int main(int argc, char** argv) {

    using namespace boost::gregorian;

    greg_year year(1400);
    greg_month month(1);

    // get a month and a year from the user
    try {
      int y, m;
      std::cout << "   Enter Year(ex: 2002): ";
      std::cin >> y;
      year = greg_year(y);
      std::cout << "   Enter Month(1..12): ";
      std::cin >> m;
      month = greg_month(m);
    }
    catch(bad_year by) {
      std::cout << "Invalid Year Entered: " << by.what() << '\n'
        << "Using minimum values for month and year." << std::endl;
    }
    catch(bad_month bm) {
      std::cout << "Invalid Month Entered" << bm.what() << '\n'
        << "Using minimum value for month. " << std::endl;
    }

    // create date and add one day to the end of month
    date d(year, month, 1);
    d=(year,month,d.end_of_month());
    date_duration dd(1);
    d += dd;
    // print date
    std::cout << d << " " << d.day_of_week() << std::endl;
    return 0;
}

示例输出:

  

输入年份(例如:2002年):2013

     

输入月份(1..12):3

     

2013年4月1日星期一

     

RUN SUCCESSFUL(总时间:6s)


使用std::vector

boost::gregorian::date d1(2013,boost::gregorian::Jan,31);
boost::gregorian::date d2(2013,boost::gregorian::Feb,28);
boost::gregorian::date d3(2013,boost::gregorian::Mar,31);

std::vector<boost::gregorian::date > v;
v.push_back(d1);
v.push_back(d2);
v.push_back(d3);

boost::gregorian::date_duration duration(1);

for(std::vector<boost::gregorian::date >::iterator it=v.begin();it!=v.end();it++){
    *it+=duration;
    std::cout << *it <<" "<< (*it).day_of_week() << std::endl;
}

答案 2 :(得分:0)

我认为问题出在2月份,因为这个月可能有29天或28天(取决于年份是否为二年级)。您可以在本月创建一个if语句。 你可以通过使用mod运算符来判断年份是否是bissextile:if%4 =! 0比2月有28天,你有29天。 希望这会对你有所帮助!

答案 3 :(得分:0)

此代码为您提供上个月的第一天和最后一天。我用它在我的应用程序中设置TDateTimePicker组件。

Word Year, Month, Day;
TDateTime datum_tdatetime = Date();

// first day of actual month
datum_tdatetime.DecodeDate(&year, &month, &day);
day = 1;
datum_tdatetime = EncodeDate(year, month, day);
// last day of previous month
datum_tdatetime -= 1;
// first day of previous month
datum_tdatetime.DecodeDate(&year, &month, &day);
day = 1;
datum_tdatetime = EncodeDate(year, month, day);