簡體   English   中英

使用C#創建包含數組和循環的日歷

[英]Creating calendar with array and loops using C#

我正在嘗試創建一個應用程序,告訴您星期幾(星期一,星期二等);當輸入2016年的日期(1月1日,9月3日等;)輸入是日期,輸出是一天該日期的一周。 必須使用for循環和if語句等循環創建它。 我不能使用庫函數。 開始日期為2016年1月1日,星期五。 這是我到目前為止,我很丟失:

    public enum Days : byte { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
    public enum Months : byte { January, February, March, April, May, June, July, August, September, October, November, December };
    class Program
    {
        public static void Main(string[] args)
        {
            const int numDays = 7;
            const int numMonths = 12;
            Months month = Months.Janurary;
            int monthCounter = 1;
            int[] daysinMonth = new int[numMonths] { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
            int[] daysofWeek = new int[numDays] {1, 2, 3, 4, 5, 6, 7};
            Days dayOfWeek = Days.Sunday;
            dayOfWeek = Days.Friday;
            foreach (month in Months )
            {

我的簡介是:

僅使用我們迄今為止所涵蓋的工具,使用嵌套循環和比較,從2016年1月1日星期五開始查找2016年特定日期的工作日名稱。

既然你不想要代碼,我會給你一些解釋和一些代碼。 然后,一旦完成所有操作,底部的完整代碼將為您提供任意日期所需的一切。

但是,您只對2016年感興趣。因此,如果您確實希望todo計算特定年份的星期幾,那么您需要的全部代碼(來自完整代碼)是兩個函數:

  • GetDayNumberFromDate
  • GetDayOfWeekFromDate

解釋只是一個小代碼

我會在靜態類中完成所有這些。 您不需要任何instance ,只需要幾個函數/方法。

在那個類中,我將聲明並初始化三個私有變量:

  • 一個由12個整數組成的數組,每個整數代表每個月的天數。 請記住,數組索引從零開始,因此您需要從月份數(1-12)中減去一個表單以獲取數組索引(0-11)。 我還建議你發表評論,指出2016年是閏年,這就是為什么二月有29天
  • 設置為2016的私有const整數(可能名為YearOfInterest )。它代表2016年數字的符號別名。Consts使您的代碼更易於維護(考慮您是否老師改變主意並說“不,為2014做”你在代碼中的六到八個地方使用了2016年 - 如果你有一個const ,你只需要更改其中一個地方。
  • 代表2016年1月1日星期五的事實。 我會使用System.DayOfWeek枚舉(是的,它是庫代碼,但你所做的任何事情都將是逐個字符的重復)。 如果你願意的話,你可以使用你的YearOfInterest const int並做一些類似的事情(如果你的老師改變了他YearOfInterest ,這將使事情有效)

這將是一個非常簡單的聲明,如下所示:

 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,即天數等於或等於少於一個月中的天數(你很方便地知道它 - 它在你的數組中(記得在索引到該數組時減去一個)。如果不滿足任何這些前提條件,拋出異常。這很重要。如果有人輸入了錯誤的數字,你可能會從你的數組中索引(這將拋出異常,但沒有關於它為什么會發生的信息)。檢查前置條件總是好的
  • 它會循環遍歷“一個月內的日期”數組,從數組的開頭到輸入月份的前一個月(減去1),總計天數。 如果有人進入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,...),你會讓那些無法拼寫“二月”的人感到不安。 只需使用月和日整數。

你會注意到的一件事是沒有嵌套循環。 沒有必要,嵌套循環可能很昂貴。 此代碼循環已經過去的月數(即少於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 ,它應該工作。 我只是非常輕微地測試它。

不要僅僅將此作為您的工作提交。 把它拆開,看看你能不能做得更好。 如果您知道如何編寫單元測試,請為每個函數編寫一個測試(我通常會這樣做,但不是今晚)。 害羞地向我展示了我按照向你展示的順序向我展示的功能。 為什么我要檢查我所做的論點而不是所有地方? 為什么我在使用它的地方使用readonlyYearZero使用const 有些代碼是非常強力的 - 看看你是否可以做得更好(一旦你有足夠好的代碼,就可以更輕松地獲得更好的代碼)。

最后,您應該能夠解釋每行代碼。

既然我明白你的任務完全集中在2016年作為一年,你的簡要要求你使用嵌套循環,以及你提供的代碼,我推薦這個:

1)定義targetMonth和targetDate(例如9月3日)2)確保daysOfWeek從星期五開始3)使用此偽代碼:

foreach mMonth in Months
    for dayOfM = 1 to daysinMonth[month] (inclusive)
        if month == targetMonth AND dayOfM == targetDate
            print dayOfWeek
            return
        else
            dayOfWeek = (dayOfWeek + 1) % 7

有用的功能:

  • Enum.GetValues(typeof(Months))將返回所有的值從Months為一個數組。
  • .OfType<Months>() (包括using System.Linq命名空間) - 您可以使用Enum.GetValues()返回的Array轉換為強類型的Months對象。
  • 您可以使用(int)dayofWeekdayOfWeek轉換為整數,然后使用(Days)5 (或者您擁有的任何整數值)返回。
  • 模數%將返回計算的其余部分。 1%7 = 1,2%7 = 2,...,7%7 == 0 - 這將允許您循環一周中的幾天。

這是我在C#中提出的解決方案,並回到偽代碼,以便不為您提供復制/可接受的答案。 我希望它有所幫助。

您可以采取的一種方法是計算從年初到指定日期的總天數,找到將該數除以7后的余數(一周中的總天數),然后添加第一個的數值一年中的某一天。

首先,我們將在他們輸入的月份之前添加每月的總天數。 要做到這一點,我們首先要弄清楚他們輸入了哪個月,然后將其轉換為一個整數,我們可以將其用作我們的daysInEachMonth數組的索引。

我們可以首先使用Enum.Parse方法獲取它們輸入的字符串的枚舉(它接受用於解析的Enum類型(在我們的例子中是Month ),以及類似“January”的字符串值,並返回enum Month值)。 然后我們可以將此值轉換為int 默認情況下,Enums的值以0開頭並遞增1 ,因此Januray0December11

int monthNumber = (int) Enum.Parse(typeof(Month), month, true);

使用此值,我們可以在此之前的每個月循環,並添加截至本月的總天數:

for (int i = 0; i < monthNumber; i++)
{
    daysFromStartOfYear += daysInEachMonth[i];
}

接下來我們將添加他們輸入的月份的日期並減去1(我們需要減去一個,因為我們正在處理從0開始的數組索引和enum值):

daysFromStartOfYear += dayDate - 1;

現在我們需要通過添加一年中第一天的數值來調整我們的數字( Sunday0Saturday6 )。 如果這沒有意義,請記住,如果他們輸入January 1 ,那么我們的daysFromStartOfYear值將為0 ,但我們知道一年中的第一天是Friday (其int值為5 )。 所以我們知道我們需要在結果中添加5 ,以便考慮第一天不是從0 (星期日)開始。

Day firstDayOfYear = Day.Friday;
daysFromStartOfYear += (int) firstDayOfYear;

現在剩下要做的就是將這個數字除以7 (一年中的天數),得到余數,並將該數字轉換為Day枚舉中的值。 如果這沒有意義,請記住,一個月中的每個Tuesday的日期都是7倍數加上該月的第一個Tuesday的值。 通過在除以7后得到剩余的值,我們得到一個06之間的數字,它將映射到我們的Day枚舉。

為了得到一個除以另一個數的余數,我們可以使用模數運算符%

int remainder = daysFromStartOfYear % numDaysInWeek;

當我們得到這個數字時,我們可以將它轉換為我們的枚舉來獲取值:

Day answer = (Day) remainder;

希望這足以讓你開始。 如果您遇到某些特定問題,請嘗試並回來,或者在下面的評論中隨意提問。

如果您只想顯示星期幾,可以這樣做:

DateTime date = new DateTime(2016, 1, 16);
Console.WriteLine(dateValue.ToString("dddd"));  // outputs Friday

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM