日历程序的偏移量

时间:2013-11-05 01:12:13

标签: c++ calendar offset

此程序接受自1753年和月份以来的任何用户输入年份并为其创建日历。但是我对偏移量有问题,这是月份开始的日子。据我所知,这只是偏移,其他一切似乎都很好。 这是我的代码。

#include <iostream>
#include <iomanip>
using namespace std;


int getMonth(int month);
int getYear(int year);
int computeOffset(int year, int month);
int numDaysYear(int year);
int numDaysMonth(int year, int month);
bool isLeapYear(int year);
void display(int year, int month, int offset);


/**********************************************************************
 * This function will call all the functions necessary to make a calendar
 * for any given month and year.
 ***********************************************************************/
int main()
{
   int numDays;
   int offset;
   int month;
   int year;

   month = getMonth(month);

   year = getYear(year);

   offset = computeOffset(year, month);

   display(year, month, offset);

   return 0;
}

/***********************************************************************
 * Gets the month number.
 **********************************************************************/
int getMonth(int month)
{
   cout << "Enter a month number: ";
   cin >> month;

   while ( month < 1 || month > 12)
   {
      cout << "Month must be between 1 and 12.\n"
           << "Enter a month number: ";
      cin >> month;
   }

   return month;
}

/***********************************************************************
 * Gets the year.
 **********************************************************************/
int getYear(int year)
{
   cout << "Enter year: ";
   cin >> year;

   while ( year < 1753)
   {
      cout << "Year must be 1753 or later.\n"
           << "Enter year: ";
      cin >> year;
   }
   return year;
}

/***********************************************************************
 * Computes the offset.
 **********************************************************************/

int computeOffset(int year, int month)
{
   int offset = 0;
   int count = year - 1753;
   for ( int iYear = 0; iYear < count; iYear++)
   {
      offset = ( offset + 365 + isLeapYear(year)) % 7;
   }

   for ( int iMonth = 1; iMonth < month; iMonth++)
   {
      offset = ( offset + numDaysMonth(year, iMonth)) % 7;
   }

   return offset;
}



/***********************************************************************
 * Computes the number of days in the given year.
 **********************************************************************/
int numDaysYear(int year)
{
   int daysYear = 365 + isLeapYear(year);
   return daysYear;
}

/***********************************************************************
 * Calculates the number of days in the given month.
 **********************************************************************/
int numDaysMonth(int year, int month)
{
   int daysMonth;

   if ( month == 1)
      daysMonth = 31;
   else if ( month == 2)
   {
      if (isLeapYear(year) == true)
         daysMonth = 29;
      else
         daysMonth = 28;
   }
   else if ( month == 3)
      daysMonth = 31;
   else if ( month == 4)
      daysMonth = 30;
   else if ( month == 5)
      daysMonth = 31;
   else if ( month == 6)
      daysMonth = 30;
   else if ( month == 7)
      daysMonth = 31;
   else if ( month == 8)
      daysMonth = 31;
   else if ( month == 9)
      daysMonth = 30;
   else if ( month == 10)
      daysMonth = 31;
   else if ( month == 11)
      daysMonth = 30;
   else if ( month == 12)
      daysMonth = 31;

   return daysMonth;
}

/***********************************************************************
 * Determines if given year is a leap year.
 **********************************************************************/
bool isLeapYear(int year)
{
   if ( year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
      return true;
   else
      return false;
}
 /**********************************************************************
 * Displays the calender table.
 **********************************************************************/
void display(int year, int month, int offset)
 {
    int dayOfWeek;
    int day;

    cout << endl;
    if ( month == 1)
       cout << "January";
    else if ( month == 2)
       cout << "February";
    else if ( month == 3)
       cout << "March";
    else if ( month == 4)
       cout << "April";
    else if ( month == 5)
       cout << "May";
    else if ( month == 6)
       cout << "June";
    else if ( month == 7)
       cout << "July";
    else if ( month == 8)
       cout << "August";
    else if ( month == 9)
       cout << "September";
    else if ( month == 10)
       cout << "October";
    else if ( month == 11)
       cout << "November";
    else if ( month == 12)
       cout << "December";


    cout << ", " << year << "\n";
    // Display month header
    cout << "  Su  Mo  Tu  We  Th  Fr  Sa\n";

    // Gets the correct offset width and end the line on the right
    //day of the week
    if (offset == 0)
    {
       day = 2;
       cout << setw(6);
    }
    else if (offset == 1)
    {
       day = 3;
       cout << setw(10);
    }
    else if (offset == 2)
    {
       day = 4;
       cout << setw(14);
    }
    else if (offset == 3)
    {
       day = 5;
       cout << setw(18);
    }
    else if (offset == 4)
    {
       day = 6;
       cout << setw(22);
    }
    else if (offset == 5)
    {
       day = 7;
       cout << setw(26);
    }
    else if (offset == 6)
    {
       day = 1;
       cout << setw(2);
    }
    else
       cout << "Error offset must be >= 0 and <=6\n";

    // The loop for displaying the days and ending the line in the right place
    for ( dayOfWeek = 1; dayOfWeek <= numDaysMonth(year, month); dayOfWeek++ )
    {
       cout << "  " <<  setw(2) << dayOfWeek;
       ++day;
       if (day == 8)
       {
          cout << "\n";
          day = 1;
       }
    }
    if ( day >= 2 && day <= 7)
       cout << "\n";

    return;
 }`

3 个答案:

答案 0 :(得分:3)

旧问题的新答案。新答案的理由:该领域更好的工具和技术。

这个答案大量使用此free, open-source header-only library。我将从最高级别开始提出此答案,并向下钻取到较低级别的详细信息。但是在任何时候我们都不得不进行详细的日历计算。 "date.h"为我们处理。

此处main

#include "date.h"
#include <iomanip>
#include <ostream>
#include <string>
#include <iostream>

int
main()
{
    print_calendar_year(std::cout);
}

这只是我的输出:

January 2016
  S  M  T  W  T  F  S
                 1  2
  3  4  5  6  7  8  9
 10 11 12 13 14 15 16
 17 18 19 20 21 22 23
 24 25 26 27 28 29 30
 31

February 2016
  S  M  T  W  T  F  S
     1  2  3  4  5  6
  7  8  9 10 11 12 13
 14 15 16 17 18 19 20
 21 22 23 24 25 26 27
 28 29

March 2016
  S  M  T  W  T  F  S
        1  2  3  4  5
  6  7  8  9 10 11 12
 13 14 15 16 17 18 19
 20 21 22 23 24 25 26
 27 28 29 30 31

April 2016
  S  M  T  W  T  F  S
                 1  2
  3  4  5  6  7  8  9
 10 11 12 13 14 15 16
 17 18 19 20 21 22 23
 24 25 26 27 28 29 30

May 2016
  S  M  T  W  T  F  S
  1  2  3  4  5  6  7
  8  9 10 11 12 13 14
 15 16 17 18 19 20 21
 22 23 24 25 26 27 28
 29 30 31

June 2016
  S  M  T  W  T  F  S
           1  2  3  4
  5  6  7  8  9 10 11
 12 13 14 15 16 17 18
 19 20 21 22 23 24 25
 26 27 28 29 30

July 2016
  S  M  T  W  T  F  S
                 1  2
  3  4  5  6  7  8  9
 10 11 12 13 14 15 16
 17 18 19 20 21 22 23
 24 25 26 27 28 29 30
 31

August 2016
  S  M  T  W  T  F  S
     1  2  3  4  5  6
  7  8  9 10 11 12 13
 14 15 16 17 18 19 20
 21 22 23 24 25 26 27
 28 29 30 31

September 2016
  S  M  T  W  T  F  S
              1  2  3
  4  5  6  7  8  9 10
 11 12 13 14 15 16 17
 18 19 20 21 22 23 24
 25 26 27 28 29 30

October 2016
  S  M  T  W  T  F  S
                    1
  2  3  4  5  6  7  8
  9 10 11 12 13 14 15
 16 17 18 19 20 21 22
 23 24 25 26 27 28 29
 30 31

November 2016
  S  M  T  W  T  F  S
        1  2  3  4  5
  6  7  8  9 10 11 12
 13 14 15 16 17 18 19
 20 21 22 23 24 25 26
 27 28 29 30

December 2016
  S  M  T  W  T  F  S
              1  2  3
  4  5  6  7  8  9 10
 11 12 13 14 15 16 17
 18 19 20 21 22 23 24
 25 26 27 28 29 30 31

可以打印出明年的日历:

using namespace date::literals;
print_calendar_year(std::cout, 2017_y);

我将从声明开始:

  

这是类型安全的系统。

文字2017_ydate::year类型的对象,而不是简单的整数。类型意味着yearmonth意味着混淆这些概念的可能性要小得多。错误往往会在编译时被捕获。

print_calendar_year非常简单:

void
print_calendar_year(std::ostream& os, date::year y = current_year())
{
    using namespace date;
    for (auto ym = y/jan; ym < y/jan + years{1}; ym += months{1})
    {
        print_calendar_month(os, ym);
        os << '\n';
    }
}

表达式year/month创建一个名为date::year_month的类型,它只不过是一个简单的结构{year, month}。因此,这个函数只是设置一个循环来迭代从y年的Jan到下一个Jan,不包括下一个Jan.它完全可读。请注意&#34;裸int s&#34;不允许。一切都有非整体类型。

print_calendar_month是橡胶遇到道路的地方:

void
print_calendar_month(std::ostream& os, date::year_month ym = current_year_month())
{
    using namespace std;
    using namespace date;
    os << format("%B %Y\n", sys_days{ym/1});
    os << "  S  M  T  W  T  F  S\n";
    auto wd = unsigned{weekday{ym/1}};
    os << string(wd*3, ' ');
    auto const e = (ym/last).day();
    for (day d = 1_d; d <= e; wd = 0)
    {
        for (; wd < 7 && d <= e; ++wd, ++d)
            os << setw(3) << unsigned{d};
        os << '\n';
    }
}

os << format("%B %Y\n", sys_days{ym/1});打印出每个月的标题(例如January 2016)。这些是类似strftime的格式化标志,它们将遵循当前全局std::locale的本地化设置(与OS支持一样多)。

子表达式ym/1创建一个类型date::year_month_day,代表指定月份和年份的第一天。 date::year_month_day是一个简单的类,持有{year, month, day}

sys_days是基于chrono::time_point的{​​{1}},精度为system_clockdays可以使用任何精度date::format system_clock并使用类似strftime的格式标记格式化它。如图所示,time_point可以转换为year_month_day。这是从sys_days字段类型到序列{year, month, day}类型的转换。

{count of days}显然会打印出日历的星期几标题。

os << " S M T W T F S\n";找到该月第一天的星期几,并使用编码auto wd = unsigned{weekday{ym/1}};weekday转换为unsigned。 [注意: gcc需要语法[Sun == 0, Sat == 6]。它不像unsigned(weekday{ym/1})的{​​{1}}。 - 结束记录]

{}只需在每月的第一天打印出3个空格,以填充第一行。

unsignedos << string(wd*3, ' ');类型的常量,等于今年和月份组合的月份的最后一天。

auto const e = (ym/last).day();

从第1天循环开始,直到该月的最后一天(包括),并在每次迭代时将date::day设置回星期日的编码。

for (day d = 1_d; d <= e; wd = 0):在您到达本周末或月末之前,请增加星期几和月中的某天。

unsigned wd:将当月的某一天转换为for (; wd < 7 && d <= e; ++wd, ++d),并将其打印成右对齐,宽度为3个空格。

打印一周后

os << setw(3) << unsigned{d};返回。

这是该计划的主要内容!几乎所有棘手的日历逻辑都封装在这两行代码中:

unsigned

为了完整性,这里有获取当前os << '\n';和当前auto wd = unsigned{weekday{ym/1}}; auto const e = (ym/last).day(); 的函数:

date::year

这两个都只是使用date::year_month将从date::year_month current_year_month() { using namespace std::chrono; using namespace date; year_month_day ymd = floor<days>(system_clock::now()); return ymd.year()/ymd.month(); } date::year current_year() { using namespace std::chrono; using namespace date; year_month_day ymd = floor<days>(system_clock::now()); return ymd.year(); } 返回的system_clock::time_point截断为精确度system_clock::now(),然后将那些日期 - 精度days转换为一个floor类型。然后,此类型会为time_pointdate::year_month_day提供getter,以选择所需的部分日历类型。

<强>更新

嗯,TemplateRex在下面问了一个问题,我一开始并不想回答,然后我无法帮助自己,因为答案强调了year的强大功能与...合作。 ; - )

问题是:

  

你能打印出这样的3x4格式的日历吗?

month

显然是这样,因为我不打算手动输入以上所有内容! ; - )

它需要重写"date.h"并引入一些新功能,最值得注意的是:

 January 2016            February 2016           March 2016          
 Su Mo Tu We Th Fr Sa    Su Mo Tu We Th Fr Sa    Su Mo Tu We Th Fr Sa
                 1  2        1  2  3  4  5  6           1  2  3  4  5
  3  4  5  6  7  8  9     7  8  9 10 11 12 13     6  7  8  9 10 11 12
 10 11 12 13 14 15 16    14 15 16 17 18 19 20    13 14 15 16 17 18 19
 17 18 19 20 21 22 23    21 22 23 24 25 26 27    20 21 22 23 24 25 26
 24 25 26 27 28 29 30    28 29                   27 28 29 30 31      
 31                                                                  

 April 2016              May 2016                June 2016           
 Su Mo Tu We Th Fr Sa    Su Mo Tu We Th Fr Sa    Su Mo Tu We Th Fr Sa
                 1  2     1  2  3  4  5  6  7              1  2  3  4
  3  4  5  6  7  8  9     8  9 10 11 12 13 14     5  6  7  8  9 10 11
 10 11 12 13 14 15 16    15 16 17 18 19 20 21    12 13 14 15 16 17 18
 17 18 19 20 21 22 23    22 23 24 25 26 27 28    19 20 21 22 23 24 25
 24 25 26 27 28 29 30    29 30 31                26 27 28 29 30      

 July 2016               August 2016             September 2016      
 Su Mo Tu We Th Fr Sa    Su Mo Tu We Th Fr Sa    Su Mo Tu We Th Fr Sa
                 1  2        1  2  3  4  5  6                 1  2  3
  3  4  5  6  7  8  9     7  8  9 10 11 12 13     4  5  6  7  8  9 10
 10 11 12 13 14 15 16    14 15 16 17 18 19 20    11 12 13 14 15 16 17
 17 18 19 20 21 22 23    21 22 23 24 25 26 27    18 19 20 21 22 23 24
 24 25 26 27 28 29 30    28 29 30 31             25 26 27 28 29 30   
 31                                                                  

 October 2016            November 2016           December 2016       
 Su Mo Tu We Th Fr Sa    Su Mo Tu We Th Fr Sa    Su Mo Tu We Th Fr Sa
                    1           1  2  3  4  5                 1  2  3
  2  3  4  5  6  7  8     6  7  8  9 10 11 12     4  5  6  7  8  9 10
  9 10 11 12 13 14 15    13 14 15 16 17 18 19    11 12 13 14 15 16 17
 16 17 18 19 20 21 22    20 21 22 23 24 25 26    18 19 20 21 22 23 24
 23 24 25 26 27 28 29    27 28 29 30             25 26 27 28 29 30 31
 30 31                                                               

此功能仅打印与print_calendar_year关联的日历的一行,是此3x4格式的核心。

我还认为让这个程序可以本地化是很有趣的,这样就可以打印出所需的第一天,以及本月和周中的本地化名称(尽可能多的您平台上的void print_line_of_calendar_month(std::ostream& os, date::year_month ym, unsigned line, date::weekday firstdow); 允许)。

线条编号为[0,无穷大]。第0行打印出月份,例如year_month ym。第1行打印出星期几标题:std::locale。然后行[2,无穷大]打印出月份的日子。

为何选择无限?

因为不同月份的行数不同,所以我希望能够告诉January 2016打印下一行,即使它不需要(因为该季度的另一个月需要它) )。因此,当您要求日历打印出它不需要的行时,它只会输出正确数量的Su Mo Tu We Th Fr Sa以用于填充。

足够的介绍,这里的功能是:

year/month

所以切换行号[0,infinity],对于每个行号,做正确的事情:

' '打印月份标题。

这会传递到void print_line_of_calendar_month(std::ostream& os, date::year_month ym, unsigned line, date::weekday firstdow) { using namespace std; using namespace date; switch (line) { case 0: os << left << setw(21) << format(os.getloc(), " %B %Y", sys_days{ym/1}) << right; break; case 1: { auto sd = sys_days{ym/firstdow[1]}; for (auto const esd = sd + weeks{1}; sd < esd; sd += days{1}) { auto d = format(os.getloc(), "%a", sd); d.resize(2); os << ' ' << d; } break; } case 2: { auto wd = weekday{ym/1}; // This line and the next are the "offset" os << string((wd-firstdow).count()*3, ' '); // referred to in the question. auto d = 1_d; do { os << setw(3) << unsigned(d); ++d; } while (++wd != firstdow); break; } default: { unsigned index = line - 2; auto sd = sys_days{ym/1}; if (weekday{sd} == firstdow) ++index; auto ymdw = ym/firstdow[index]; if (ymdw.ok()) { auto d = year_month_day{ymdw}.day(); auto const e = (ym/last).day(); auto wd = firstdow; do { os << setw(3) << unsigned(d); } while (++wd != firstdow && ++d <= e); os << string((firstdow-wd).count()*3, ' '); } else os << string(21, ' '); break; } } } 0.的{​​{1}}以获取本地化的月份名称。

format打印出星期几标题。

这会传递locale os的{​​{1}}以获取本地化的工作日名称,并打印前2个字符。 (不幸的是)当这些是多字节字符时,这只是近似正确,但这篇文章主要是关于日历,而不是Unicode。

1.打印出第一周,可能会以空格为前缀。前缀的空格数为3 *(该月的第一天超过一周的第一天的天数)。然后追加几天直到你到达一周的最后一天。请注意,工作日减法始终是模7,因此您不必担心几周内的基础编码。工作日形成一个圆形范围。这确实需要与format相对应的内容,而不是传统的locale在一周内的所有日子循环。

os。啊,这是有趣的部分。

2.中有一个名为do-while的类型,它是一种存储for的类型。这就是你如何指定母亲节:5月的第二个星期日:3 - infinity。这个表达式创建了一个结构"date.h"(粗略地说)。因此,如果year_month_weekday落在这里,那么我们正在寻找本月和一年的[第一个,最后一个]星期日,其中确切的索引取决于{year, month, weekday, unsigned},以及我们是否打印了星期天在第2行。

同样关键,此库允许使用任何索引:

sun[2]/may/2016

{2016, 5, 0, 2}可以是1,或者可能是57.上面的行编译并且不是运行时错误。

但是几个月不能有57个星期日(或星期一或其他什么)!

没问题。您可以询问switch是否为有效日期。这就是下一行的作用:

line

如果日期有效,那么您有工作要做。否则你只需要打印出一个空白行。

如果我们有工作要做,请将auto ymdw = ym/firstdow[index]; 转换为index,以便您可以从中获取当天(ym/firstdow[index])。找到这个月的最后一天:

if (ymdw.ok())

然后从一周的第一天开始迭代到最先出的那个:月末或一周的最后一天。打印每个地点的当天。然后,如果你没有在一周的最后一天结束,请打印空格以填充到一周的最后一天。

我们已完成year_month_weekday!请注意,在此级别上永远不会输出换行符。在这个级别上甚至没有输出月间填充。每个日历的宽度都是21 year_month_day,并且可以打印到任意数量的行。

现在我们需要另一个小实用程序:在开始使用空行填充之前,日历月需要的行数是多少?

d

这是该月的天数,加上从一周的第一天到该月的第一天的天数,再加上星期几标题和年份的另外两行 - 月标题。最后的分数周被四舍五入!

注意:

  1. 从一周的第一天到该月的第一天的天数只是:auto const e = (ym/last).day();

  2. 此处的天数在此处编码为print_line_of_calendar_month。请注意,char不是有效unsigned number_of_lines_calendar(date::year_month ym, date::weekday firstdow) { using namespace date; return ceil<weeks>((weekday{ym/1} - firstdow) + ((ym/last).day() - day{0})).count() + 2; } ,但在减法中仍然有用:(weekday{ym/1} - firstdow)会得到((ym/last).day() - day{0}) day{0}的结果。另一种说法是day

  3. 请注意,此处day - day用于将chrono::duration的数量转换为days的数量,如果转换不是((ym/last).day() - day{1} + days{1}),则向上舍入到下一个ceil<weeks>精确。 1周== 1排。本综述说明了在本周最后一天之前结束的最后一周。

  4. 现在days可以根据这些原语重写:

    weeks

    首先计算每个月需要多少行:

    weeks

    然后,对于每个&#34;日历行&#34;,通过搜索print_calendar_year的正确子集找到该行所需的行数。

    然后对于每一行,以及每个&#34;日历列&#34;,打印出该列的相应日历月份的行。

    每行打印一个void print_calendar_year(std::ostream& os, unsigned const cols = 3, date::year const y = current_year(), date::weekday const firstdow = date::sun) { using namespace date; if (cols == 0 || 12 % cols != 0) throw std::runtime_error("The number of columns " + std::to_string(cols) + " must be one of [1, 2, 3, 4, 6, 12]"); // Compute number of lines needed for each calendar month unsigned ml[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; for (auto& m : ml) m = number_of_lines_calendar(y/month{m}, firstdow); for (auto r = 0u; r < 12/cols; ++r) // for each row { const auto lines = *std::max_element(std::begin(ml) + (r*cols), std::begin(ml) + ((r+1)*cols)); for (auto l = 0u; l < lines; ++l) // for each line { for (auto c = 0u; c < cols; ++c) // for each column { if (c != 0) os << " "; print_line_of_calendar_month(os, y/month{r*cols + c+1}, l, firstdow); } os << '\n'; } os << '\n'; } }

    在每个日历行之后,打印// Compute number of lines needed for each calendar month unsigned ml[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; for (auto& m : ml) m = number_of_lines_calendar(y/month{m}, firstdow);

    请注意,我们仍然不需要沉入日历算术中。在这个级别,我们需要知道&#34;每周7天&#34;,&#34;每天3个空间&#34;每个日历行&#34; 12 / cols个月&#34;。

    在macOS上这个驱动程序:

    ml

    输出:

    '\n'

    您的版本可能因您的std :: lib / OS支持本地化的程度而异。但是现在你可以使用任何一年的任何一年中的任何一天作为第一天的任何一天,以12个月的任何除数([1,2,3,4,6,12])打印你的日历。一周,并使用任何语言环境(模块OS支持语言环境)。

    这是'\n'

    的输出
    using namespace date::literals;
    std::cout.imbue(std::locale("de_DE"));
    print_calendar_year(std::cout, 3, 2016_y, mon);
    

答案 1 :(得分:1)

此代码不能解决您的问题(我无法分辨出问题所在),但可能会将其与您的版本进行对比。

#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

using namespace std;


int getMonth();
int getYear();
int computeOffset(int year, int month);
int numDaysYear(int year);
int numDaysMonth(int year, int month);
bool isLeapYear(int year);
void display(int year, int month, int offset);


/**********************************************************************
 * This function will call all the functions necessary to make a calendar
 * for any given month and year.
 ***********************************************************************/
int main()
{
   int offset;
   int month;
   int year;

   month = getMonth();
   year = getYear();
   offset = computeOffset(year, month);

   display(year, month, offset);

   return 0;
}

/***********************************************************************
 * Gets the month number.
 **********************************************************************/
int getMonth()
{
   int month = 0;
   cout << "Enter a month number: ";
   cin >> month;

   while (month < 1 || month > 12)
   {
      cout << "Month must be between 1 and 12.\n"
           << "Enter a month number: ";
      cin >> month;
   }

   return month;
}

/***********************************************************************
 * Gets the year.
 **********************************************************************/
int getYear()
{
   int year = 0;
   cout << "Enter year: ";
   cin >> year;

   while ( year < 1753)
   {
      cout << "Year must be 1753 or later.\n"
           << "Enter year: ";
      cin >> year;
   }
   return year;
}

/***********************************************************************
 * Computes the offset.
 **********************************************************************/

int computeOffset(int year, int month)
{
   int offset = 0;
   int count = year - 1753;
   for (int iYear = 0; iYear < count; iYear++)
   {
      offset = (offset + 365 + isLeapYear(year)) % 7;
   }

   for (int iMonth = 1; iMonth < month; iMonth++)
   {
      offset = (offset + numDaysMonth(year, iMonth)) % 7;
   }

   return offset;
}



/***********************************************************************
 * Computes the number of days in the given year.
 **********************************************************************/
int numDaysYear(int year)
{
   return 365 + isLeapYear(year);
}

/***********************************************************************
 * Calculates the number of days in the given month.
 **********************************************************************/
int numDaysMonth(int year, int month)
{
   std::vector<int> days { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
   int daysMonth = days[month-1];

   if (month == 2 && isLeapYear(year))
   {
       daysMonth = 29;
   }

   return daysMonth;
}

/***********************************************************************
 * Determines if given year is a leap year.
 **********************************************************************/
bool isLeapYear(int year)
{
   return (year % 400 == 0) || (year % 100 != 0 && year % 4 == 0);
}
 /**********************************************************************
 * Displays the calender table.
 **********************************************************************/
void display(int year, int month, int offset)
 {
    int day;

    cout << endl;
    std::vector<std::string> mth { "January", "February", "March",
      "April", "May", "June", "July", "August", "September",
      "October", "November", "December" };
    cout << mth[month-1];

    cout << ", " << year << "\n";
    // Display month header
    cout << "  Su  Mo  Tu  We  Th  Fr  Sa\n";

    // Gets the correct offset width and end the line on the right
    // day of the week
    if (0 <= offset && offset <= 6)
    {
        day = ((offset + 1) % 7) + 1;
        cout << setw((day - 2) * 4 + 6);
    }
    else
       cout << "Error offset must be >= 0 and <=6\n";

    // The loop for displaying the days and ending the line in the right place
    for (int dayOfWeek = 1; dayOfWeek <= numDaysMonth(year, month); dayOfWeek++ )
    {
       cout << "  " <<  setw(2) << dayOfWeek;
       ++day;
       if (day == 8)
       {
          cout << "\n";
          day = 1;
       }
    }
    if (day >= 2 && day <= 7)
       cout << "\n";

    return;
 }

答案 2 :(得分:0)

我知道这是在一年前发布的,但我确实为未来的访问者提供了解决方案。在原始帖子的computeOffset函数中,该函数实际上并不计算总共过去了多少天。你需要计算已经过了多少年,那些年里有多少天,以及那些年后几个月的日子,如果这有意义的话。这是我的工作computeOffset函数的代码:

int computeOffset(int month, int year)
 {
   int numDaysYear = 0;
   int yearCounter = 0;
   int monthCounter = 0;
   int months = 1  // NOT the same at the "month" variable coming in

   // This loop counts how many days have passed in the full years up to the given year
   for (int iYear = 1753; iYear < year; iYear++)
   {
      numDaysYear = numDaysYear + 365;

      if (isLeapYear(iYear))                          
         yearCounter++;
   }

   // This loop counts the days in the remaining months after all the years
   for (int iMonth = 1; iMonth < month; iMonth++)
   {
      monthCounter = monthCounter + numDaysMonth(months, year);  //MONTHS not month
      months++;
   }

   int offset = (numDaysYear + yearCounter + monthCoutner) % 7;

   return offset;

希望这是有道理的,对不起,如果某些变量有奇怪的名字,或者风格不是你习惯的。希望这有帮助!