既然你不需要代码,我就给你一些解释,只给你一点代码。然后,一旦这一切都完成了,在它的底部会有完整的代码,它将为您提供任意日期所需的一切。
但是,您只对 2016 年感兴趣。因此,如果您确实想要计算特定年份的星期几,那么您所需要的(来自完整代码)就是类声明和两个功能:
- GetDayNumberFromDate
- GetDayOfWeekFromDate
解释和一小段代码
我会在一个静态类中完成所有这些。您不需要任何instance,只需几个函数/方法即可。
在该类中,我将声明并初始化三个私有变量:
- 12 个整数的数组,每个整数代表每个月的天数。请记住,数组索引从零开始,因此您需要从月份数 (1-12) 中减去一个来获得数组索引 (0-11)。我还建议您发表评论,指出 2016 年是闰年,这就是为什么 2 月有 29 天
- 一个私有的
const整数(可能命名为YearOfInterest),设置为2016。它代表数字2016的符号别名。常量使你的代码更容易维护(考虑如果你的老师改变主意说“不,为 2014 年做”,并且您在代码中的 6 或 8 个位置使用了 2016 - 如果您有 const,您只需要更改其中一个位置。
- 表示 2016 年 1 月 1 日是星期五这一事实。我会使用 System.DayOfWeek 枚举(是的,它是库代码,但你所做的任何事情都将是一个字符一个字符的重复)。如果你愿意,你可以使用你的
YearOfInterest const int 并做类似的事情(如果你的老师改变了对这一年的想法,这将使事情顺利进行)
这将是一个非常简单的声明,如下所示:
private readonly static DayOfWeek Jan1DayOfWeek = new DateTime (YearOfInterest, 1, 1).DayOfWeek;
我认为这比仅仅说:
private readonly static DayOfWeek Jan1DayOfWeek = DayOfWeek.Friday;
请记住,枚举从零开始编号(默认情况下),因此星期日为 0,星期六为 6。
完成后,我将创建两个函数:
- 计算某个日期的
Day Number(即,一年中到该日期为止的天数(1 月 1 日的天数是 1,2 月 3 日的天数是 34 )。
- 调用您的
Day Number 函数(即获取整数)并返回一周中的某一天。
第一个函数(我们称之为GetDayNumberFromDate)采用两个整数日期(月和日)做了三件事:
- 它会检查您的先决条件。由于这两个数字都是用户输入的,并且用户犯了错误,因此您需要确保两个数字都等于或大于 1、月数等于或小于 12、日数等于或小于一个月中的天数(您可以方便地知道 - 它在您的数组中(请记住在索引该数组时减去一个)。如果不满足任何这些先决条件,则抛出异常。这很重要。如果如果有人输入了错误的数字,您可能会从数组中索引(这会引发异常,但没有关于它发生原因的信息)。检查前置条件总是好的
- 它循环遍历您的“一个月中的天数”数组,从数组的开头到输入月份的前一个月(减一)对天数求和。如果有人输入 4 月 4 日,您要添加 1 月 (31)、2 月 (29) 和 3 月 (31) 的天数。这将使您到达月初(嗯,上个月的最后一天)。
- 它会在输入的月份中添加日期 - 让您返回当前日期。
由于您希望在 for 循环上进行指导,因此该循环最终将如下所示:
int dayCount = 0;
for (int i = 0; i < month - 1; ++i) {
dayCount += daysPerMonth[i];
}
在循环结束时,dayCount 会告诉您从年初到输入日期前一个月月底的天数。当您添加输入的月份中的某一天时,您会得到day number。
最后,最后一个函数(称为GetDayOfWeekFromDate)也采用相同的两个整数(月份编号和月份编号)。它调用GetDayNumberFromDate 来获取输入日期的天数,减一(因为从 0 开始的计算比从 1 开始的计算要容易得多)并添加与我们在开头声明的 Jan1DayOfWeek 等效的整数((int) Jan1DayOfWeek )。
有了这个,我会用那个数字做一个“模数 7”运算 (thatNumber % 7)。模数是计算整数除法余数的结果。这将为您提供一个介于 0 和 6 之间的数字。如果您将该数字重新转换为 DayOfWeek,它将为您提供周日和周六之间的一周中的一天。对该结果致电ToString,您就会得到结果。
如果结果不合格(尤其是差一分),请不要感到惊讶。第一次做到这一点很棘手。这就是调试的用武之地。
顺便说一下,我不会尝试解析像“1 月 1 日”这样的日期。你真的需要注意缩写(Jan,Feb,...),你会让那些不会拼写“February”的人不高兴。只需使用月份和日期整数。
在所有这些中您会注意到的一件事是没有嵌套循环。没有必要这样做,嵌套循环可能很昂贵。此代码循环过去的月数(即少于 12 次)。如果您要循环一个月和一个月中的几天,您将循环 12 次 30 次(即大约 366 次)。 12 是一个较小的数字
完整代码如下:
我不知道你学到了什么,所以这主要是在 2005 年左右的非常基本的 C# 中。
首先是一个带有一些基本“常量”的静态类:
static class FigureDate {
private static readonly int[] _leapYearDaysPerMonth = new int[] { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
private static readonly int[] _normalYearDaysPerMonth = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
private const int YearZero = 1900;
//Sunday is zero in DayOfWeek
private readonly static DayOfWeek _day0 = new DateTime(YearZero, 1, 1).DayOfWeek;
}
(顺便说一句,DayOfWeek 是在 System 命名空间中定义的 enum,因此您可以免费获得它。星期日是 0)
我将在该类中添加更多内容 - 所有内容(即下面的所有函数)都在其中。
首先,特定的年份是闰年(这绝非易事):
public static bool IsLeapYear (int year) {
if (year % 400 == 0) {
return true;
}
if (year % 100 == 0) {
return false;
}
//otherwise
return (year % 4) == 0;
}
然后我计算从“第 0 天”开始的闰年如何过去(幸运的是,1900 年不是闰年,因此减少了一个错误的可能性):
public static int NumLeapYearsToStartOfYear(int year) {
if (year < YearZero) {
throw new ArgumentException($"Only Years from {YearZero} onwards can be evaluated");
}
//do it brute force
int count = 0;
for (var y = YearZero; y <= year; ++y) {
if (IsLeapYear(y)) {
++count;
}
}
return count;
}
有了这个,我可以算出从“第 0 天”到感兴趣的年初有多少天:
public static int DaysToStartOfYear(int year) {
return (year - YearZero) * 365 + NumLeapYearsToStartOfYear(year);
}
现在,换个角度,找出有趣的一天是什么“天数”(记住,2 月 3 日是第 34 天)。
public static int GetDayNumberFromDate (int year, int month, int day) {
int[] daysPerMonth = IsLeapYear(year) ? _leapYearDaysPerMonth : _normalYearDaysPerMonth;
if (month < 1 || month > 12) {
throw new ArgumentException($"Month number ({month}) is invalid");
}
if (day < 1 || day > daysPerMonth[month - 1]) {
throw new ArgumentException($"Day/Month combination invalid for month:{month}, day:{day}");
}
int dayCount = 0;
for (int i = 0; i < month - 1; ++i) {
dayCount += daysPerMonth[i];
}
return dayCount + day;
}
最后把它们放在一起。正如您可能想象的那样,此代码中有一个问题。我使用日期的“天数”,它在 1...N 范围内,我们真的希望它是 0...N-1。所以,我减去 1。
public static DayOfWeek GetDayOfWeekFromDate (int year, int month, int day) {
int totalDays = DaysToStartOfYear(year) + GetDayNumberFromDate(year, month, day) - 1 + (int)_day0;
return (DayOfWeek)(totalDays % 7);
}
如果您调用该函数,然后在结果上调用ToString,它应该工作。我只是对它进行了非常轻微的测试。
请不要仅仅将其作为您的作品提交。把它拆开,看看你能不能做得更好。如果您知道如何编写单元测试,请为每个函数编写一个测试(我通常会这样做,但今晚不会)。弄清楚我向你展示了我展示给你的功能,我展示给你的顺序是我展示给你的。为什么我在我做的地方而不是到处检查论点?为什么我在使用它的地方使用readonly,而在YearZero 使用const?一些代码非常蛮力 - 看看你是否可以做得更好(一旦你有足够好的代码,获得更好的代码会容易得多)。
最后,你应该能够解释每一行代码了。