当前位置: 首页 > 知识库问答 >
问题:

计算下个月开始日的算法

顾磊
2023-03-14

我正在写一个简单的日历课程。我正在尝试重载操作员,以便使用它将日历移动到下个月。然而,我找到下个月开始日期的算法并不完全正确。

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。start Day、previousStartDay、nextStartDay、月份和年份都是私有类变量

当我在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;

共有3个答案

单于翰飞
2023-03-14

我认为问题在于2月,因为这个月可能有29天或28天(取决于一年是否为双性年)。您可以创建本月的if语句。你可以通过使用mod操作符if:the year%4=(如果:年份%4=)!2月只有28天,而2月只有29天。希望这对你有帮助!

梅安平
2023-03-14

boost给了你几个很好的例子。在这里,我基于示例中的一个实现了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日星期一

运行成功(总时间: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;
}
谭灿
2023-03-14

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

你的findNextStartDay算法将发现monthlength等于3(31-28),那么一天将是2(8-6),也就是周二(2),而不是周一(1)。。。

让我们通过运行算法(findNextStartDay的第一个版本)来了解为什么这是错误的:

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

二月:28-28=0,天=5(星期五)0=5(星期五),这是三月的正确开始日期。

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

问题是,当你减去星期六导致溢出(超过星期六)时,你在计算中漏掉了一天(即:你比你想要的少减去一天)。

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

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

在你的算法中,超过6的1(即7)返回到1,去掉可怜的0(星期日),并使一周中的一天在每次结束时消失。

如果您减去星期六1,您将获得下个月的正确日期,以防“星期天溢出”。

简而言之,改变这一行:

day -= Saturday;

day -= (Saturday + 1);

但是,请考虑将您的代码审查为更干净的算法版本!

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

day = ((day + monthlength) % (Saturday + 1))
 类似资料:
  • 我试图在我正在创建的C#应用程序中显示两个日期之间的年、月和日。(使用控制台进行测试) 我正在使用NodaTime来实现这一点,但在接下来的几个月里,我遇到了一些问题。 我已经阅读了这里的大部分问题和答案,但没有找到任何我可以从中受益的东西。 大多数时候函数工作但有时它不添加月如果天 我使用这个代码进行测试 (2017, 10, 16)和(2018, 1, 15)应该显示为3个月,但它们显示为2个

  • 问题内容: 使用date(1970年1月1日)作为时间操纵的默认标准有什么原因吗?我已经在Java和Python中看到了这个标准。我知道这两种语言。还有其他遵循相同标准的流行语言吗? 请描述。 问题答案: 这是Unix时间的标准。 Unix时间或POSIX时间是一种用于描述时间点的系统,时间点定义为自1970年1月1日午夜多点协调世界时(UTC)起经过的秒数,不包括leap秒。

  • 我正在开发一个程序,它采用开始日期和结束日期,并返回年、月和日的不同值。每个类别都有自己的代码部分,这是我一直在使用的代码,到目前为止,它一直是半精确的,直到几天(有时是几个月。我甚至不想在这一点上愚弄闰年) Ex Start:04/10/2000 End:04/10/2006应该给我6年零个月零天。 年份代码: 月份代码: 天数代码:我已经尝试了多个版本,但没有太大的成功,例如,我可以计算天数之

  • 如何在Android中获取和显示日期以来的天数,月份和年份? 例如,假设上一个日期是: 今天的日期是: 我希望它能这样说: 我想我需要得到这样的总天数: 但是我如何将天数转换为年、月和天呢?请记住,并不是所有的月都有31天。 因为这样我只会 结果呢。但我希望它更像是1年2个月28天。 有更好的解决方案吗? 我也想得到像这样的旧日期在一个变量: 但是上面的代码根本不起作用。是的,我知道变量在kotl

  • 问题内容: 我有两个约会: 开始日期: 结束日期: 在上述两个日期之间的91天持续时间,我希望我的代码返回3个月的持续时间,但以下方法仅返回2个月。有谁有更好的建议?还是你们认为这是Java 8中的错误?工期为91天,仅返回2个月。 非常感谢你的帮助。 方法1: 方法2: 方法3: 我尝试使用Joda库而不是Java 8 API,它可以工作。它会返回3,它看起来像Java持续时间月份的计算也使用了

  • 问题内容: 如果不使用PHP 5.3的date_diff函数(我使用的是PHP 5.2.17),是否有一种简单而准确的方法?我正在考虑以下代码,但是我不知道如何计算leap年: 我正在尝试计算一个人的月数。 问题答案: 您可能还希望将某天包括在内,具体取决于您是否指的是 整个 月。希望你能明白。