C#快速入門教程(25)—— 日期與時間

曹化宇發表於2018-11-06

在System名稱空間裡定義了日期和時間處理的基礎資源,如DateTime和TimeSpan結構型別;本課,除了使用這些基礎資源,我們還將討論如何獲取中國農曆資訊,首先,我們從DateTime結構的使用開始。

DateTime結構

DateTime結構中的MinValue和MaxValue兩個欄位,分別定義了處理日期和時間的最小值和最大值,其中,MinValue表示公元0001年1月1日0時0分0秒。此外,在.NET Framework中處理時間的最小單位是Tick,它表示萬之一秒(即100毫微秒),在DateTime中的Ticks屬性則表示儲存時間距離DateTime.MinValue值的Tick值。

除了Ticks屬性,我們常用用的屬性還有Year、Month、Day、Hour、Minute、Second、Millisecond等。獲取一個時間點時,可以通過建構函式、Now屬性、Today屬性等,其中:

  • Now屬性可以獲取計算機的當前日期和時間。
  • Today屬性獲取計算當前日期,其中的時間設定為0點0分0秒。

使用DateTime結構的建構函式時,可以使用多個版本,常用的有:

  • DateTime(long),使用Tick值初始化時間。
  • DateTime(int,int,int),使用年、月、日初始化時間。
  • DateTime(int,int,int,int,int,int),使用年、月、日、時、分、秒初始化時間。

獲取時間值後,還可以使用一些方法顯示為常用的格式,如:

  • ToLongDateString(),返回長日期格式字串。
  • ToShortDateString(),返回短日期格式字串。
  • ToLongTimeString(),返回長時間格式字串。
  • ToShortTimeString(),返回短時間格式字串。

下面的程式碼演示了這四個方法的輸出結果,請注意,其輸出格式預設使用計算機系統設定的區域中的日期時間格式。

    static void Main(string[] args)
    {
        DateTime dt = new DateTime(2018, 9, 23, 11, 16, 30);
        Console.WriteLine(dt.ToLongDateString());
        Console.WriteLine(dt.ToShortDateString());
        Console.WriteLine(dt.ToLongTimeString());
        Console.WriteLine(dt.ToShortTimeString());
    }

我的計算機區域設定當然是中國,程式碼輸出結果如下圖所示。

enter image description here

除獲取日期和時間資訊,我們還可以通過DateTime結構進行一些簡單的日期和時間推算,如獲取某個時間點早一些或晚一些時間點,此時,可以使用一系列的AddXXX()方法,如下面的程式碼,我們使用AddDays()推算早三天和晚三天的時間點。

    static void Main(string[] args)
    {
        DateTime dt = new DateTime(2018, 9, 23, 11, 16, 30);
        Console.WriteLine(dt.AddDays(-3).ToString());
        Console.WriteLine(dt.AddDays(3.5).ToString());
    }

程式碼執行結果如下圖所示。

enter image description here

我們可以看到,當AddXXX()方法的引數為負數時,就是推算早一些的時間點,而引數為正數時則是推算晚一些的時間點。除了使用DateTime結構中的AddXXX()方法進行日期和時間的推算,我們還可以藉助TimeSpan結構進行日期和時間的計算工作。

TimeSpan結構

下面的程式碼,我們使用TimeSpan結構進行DateTime資料的加、減運算。

    static void Main(string[] args)
    {
        DateTime dt1 = new DateTime(2018, 9, 23, 11, 16, 00);
        TimeSpan ts = new TimeSpan(1, 30, 0);
        DateTime dt2 = dt1 + ts;
        Console.WriteLine(dt2.ToString());
        DateTime dt3 = dt1 - ts;
        Console.WriteLine(dt3.ToString());
    }

本例中,我們定義的TimeSpan為1小時30分,然後,使用dt1分別進行加(晚一些)、減(早一些)運算,執行結果如下圖所示。

enter image description here

實際應用中,我們使用兩個DateTime資料進行加、減運算時,也會返回一個TimeSpan資料,此時,可以獲取兩個時間點間隔的小時、分、秒等資料,如下面的程式碼。

    static void Main(string[] args)
    {
        DateTime dt1 = new DateTime(2018, 9, 23, 11, 16, 00);
        DateTime dt2 = new DateTime(2018, 9, 26, 15, 36, 25);
        TimeSpan ts = dt2 - dt1;
        Console.WriteLine(ts.Days);
        Console.WriteLine(ts.Hours);
        Console.WriteLine(ts.Minutes);
        Console.WriteLine(ts.Seconds);
    }

本例顯示了兩個時間點分別計算的天數、小時數、分鐘數和秒數,執行結果如下圖所示。

enter image description here

此外,如果需要兩個時間點完整的間隔資料,可以使用TimeSpan結構中的Ticks屬性獲取。

獲取中國農曆資訊

世界上很多文明都有自己的歷法,中國的農曆就是其中之一,相信大家在春節時就會感覺到其威力有多大。在.NET Framework類庫中,包含了處理各種曆法的資源,它們包含在System.Globalization名稱空間,以下程式碼請注意引用此名稱空間。

下面的程式碼,我們首先計算出農曆所需要的資料。

/*
 * CChineseCalendar類,處理農曆
 * 
 */

using System;
using System.Globalization;


namespace ConsoleTest
{
    public class CChineseCalendar
    {
        private DateTime myDate;
        // 建構函式
        public CChineseCalendar(DateTime dt)
        {
            myDate = dt;
            SetLunar();
        }
        //
        public CChineseCalendar() : this(DateTime.Now)
        { }
        //
        public CChineseCalendar(int year, int month, int day)
            :this(new DateTime(year, month, day))
        { }
        // 計算農曆資訊
        private void SetLunar()
        {
            ChineseLunisolarCalendar cale = 
                new ChineseLunisolarCalendar();
            // 甲子年份
            Year = 
                cale.GetSexagenaryYear(myDate);
            // 地支
            TerrestrialBranch = 
                cale.GetTerrestrialBranch(Year);
            // 天干
            CelestialStem = 
                cale.GetCelestialStem(Year);
            // 月份(1-13),注意處理閏月情況
            Month = cale.GetMonth(myDate);
            // 閏月是第幾個月,注意冬月和臘月在陽曆第二年的情況
            // 如是8就是閏七月
            if (Month > 10 && myDate.Month < 3)
                LeapMonth = cale.GetLeapMonth(myDate.Year - 1);
            else
                LeapMonth = cale.GetLeapMonth(myDate.Year);
            // 日子
            Day = cale.GetDayOfMonth(myDate);
        }
        //
        public int Year { get; private set; }
        public int Month { get;private set; }
        public int LeapMonth { get; private set; }
        public int Day { get; private set; }
        public int TerrestrialBranch { get; private set; }
        public int CelestialStem { get; private set; }
        //
    }// end class CChineseCalendar
}

程式碼中,我們定義了一些屬性,如:

  • Year屬性,農曆年份,表示甲子中的第幾年,取值從1到60。
  • Month屬性,農曆月份值,取值從1到13,注意農曆有閏月的情況。
  • LeapMonth屬性,閏月值,如年份中沒有閏月為0,如為8則表示閏7月,以此類推。如果陽曆為一月或二月,則應注意是不為前一年的冬月或臘月,此時,計算閏月值需要使用前一年的陽曆年份。
  • Day屬性,農曆日期,如初一為1,取值從1到30。
  • TerrestrialBranch屬性,地支值,1到12,同時分別對應了十二生肖。
  • CelestialStem屬性,天干值,1到10。

關鍵的資料計算都放在SetLunar()方法中,其中關於各項資料的獲取請注意引數的不同,有的是使用陽曆日期(DateTime型別),有的是使用甲子年份,有的是使用陽曆年份。私有欄位myDate則用於儲存物件中處理的陽曆日期值。

此外,在CChineseCalendar類中還定義了三個建構函式,分別是:

  • CChineseCalendar(DateTime dt),通過DateTime資料構建物件。
  • CChineseCalendar(),通過計算機當前時間構建物件。
  • CChineseCalendar(int year, int month, int day),通過年、月、日構建物件。

接下來,我們可以通過獲取的相關資料,以合理的形式顯示出農曆資訊,如下面的程式碼,首先是年份名稱的顯示。

    /* 年份名稱 */
    private static string[] yearNames = {"",
        "甲子","乙丑","丙寅","丁卯","戊辰","己巳","庚午","辛未","壬申","癸酉",
        "甲戌","乙亥","丙子","丁丑","戊寅","己卯","庚辰","辛巳","壬午","癸未",
        "甲申","乙酉","丙戌","丁亥","戊子","己丑","庚寅","辛卯","壬辰","癸巳",
        "甲午","乙未","丙申","丁酉","戊戌","己亥","庚子","辛丑","壬寅","癸卯",
        "甲辰","乙巳","丙午","丁未","戊申","己酉","庚戌","辛亥","壬子","癸丑",
        "甲寅","乙卯","丙辰","丁巳","戊午","己未","庚申","辛酉","壬戌","癸亥"};
    //
    public string YearName
    {
        get { return yearNames[Year]; }
    }

程式碼中,我們定義了yearNames資料,用於儲存甲子的60個年份名稱;請注意,陣列的第一個成員定義為空字元中,這裡只是一個佔位,這樣就可以直接使用年份的值(1到60)作為索引值使用了。

月份和日期的名稱獲取與年份名稱類似,只是需要注意,月份要處理閏月的情況,如下面的程式碼。

    /* 月份名稱 */
    private static string[] monthNames =
        {"", "正月", "二月", "三月", "四月", "五月", "六月",
            "七月", "八月", "九月", "十月", "冬月", "臘月"};
    // 給出當前月份名稱
    public string MonthName
    {
        get
        {
            if (LeapMonth <= 0 || Month < LeapMonth)
                return monthNames[Month];
            else if (LeapMonth == Month)
                return CStr.Append("閏", monthNames[Month - 1]);
            else
                return monthNames[Month - 1];
        }
    }
    /* 日子名稱 */
    private static string[] dayNames =
        {"", "初一", "初二", "初三", "初四", "初五",
            "初六", "初七", "初八", "初九", "初十",
            "十一", "十二", "十三", "十四", "十五",
            "十六", "十七", "十八", "十九", "二十",
            "廿一", "廿二", "廿三", "廿四", "廿五",
            "廿六", "廿七", "廿八", "廿九", "三十"};
    // 當前日期名稱
    public string DayName
    {
        get { return dayNames[Day]; }
    }

下面是通過地支的值獲取十二生肖名稱的程式碼。

    // 生肖對應地支
    private static string[] animalNames = {"",
        "鼠","牛","虎","兔","龍","蛇","馬","羊","猴","雞","狗","豬" };
    //
    public string AnimalName
    {
        get { return animalNames[TerrestrialBranch]; }
    }
    //
    public int Animal
    {
        get { return TerrestrialBranch; }
    }

最後,我們定義一個ToStr()方法,用於顯示完成的農曆資訊,如下面的程式碼。

    //
    public string ToStr()
    {
        return "{0}({1})年 {2}{3}".Combine(
            YearName, AnimalName, MonthName, DayName);
    }

下面,我們測試CChineseCalendar類的使用。

    static void Main(string[] args)
    {
        DateTime dt1 = new DateTime(2018, 9, 23, 11, 16, 00);
        CChineseCalendar cale = new CChineseCalendar(dt1);
        Console.WriteLine(cale.ToStr());
    }

程式碼執行結果如下圖所示。

enter image description here

實際應用中,大家還可以根據需要擴充套件CChineseCalendar類的功能。

CHY軟體小屋原創作品!

相關文章