今天是女神节,来一篇日历显示当前日期与农历,以及显示特殊节日
一、新建窗体应用程序CustomCalendarDemo
将默认的Form1重命名为FormCustomDate,窗体FormCustomDate设计如图:
二、窗体设计器代码如下(FormCustomDate.Designer.cs):
namespace CustomCalendarDemo
{
partial class FormCustomDate
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.cboYear = new System.Windows.Forms.ComboBox();
this.cboMonth = new System.Windows.Forms.ComboBox();
this.dgvDate = new System.Windows.Forms.DataGridView();
this.rtbInfo = new System.Windows.Forms.RichTextBox();
this.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column3 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column4 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column5 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column6 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column7 = new System.Windows.Forms.DataGridViewTextBoxColumn();
((System.ComponentModel.ISupportInitialize)(this.dgvDate)).BeginInit();
this.SuspendLayout();
//
// cboYear
//
this.cboYear.FormattingEnabled = true;
this.cboYear.Location = new System.Drawing.Point(27, 12);
this.cboYear.Name = "cboYear";
this.cboYear.Size = new System.Drawing.Size(157, 20);
this.cboYear.TabIndex = 0;
this.cboYear.SelectedIndexChanged += new System.EventHandler(this.cboYear_SelectedIndexChanged);
//
// cboMonth
//
this.cboMonth.FormattingEnabled = true;
this.cboMonth.Location = new System.Drawing.Point(215, 12);
this.cboMonth.Name = "cboMonth";
this.cboMonth.Size = new System.Drawing.Size(121, 20);
this.cboMonth.TabIndex = 1;
this.cboMonth.SelectedIndexChanged += new System.EventHandler(this.cboMonth_SelectedIndexChanged);
//
// dgvDate
//
this.dgvDate.AllowUserToAddRows = false;
this.dgvDate.AllowUserToDeleteRows = false;
this.dgvDate.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dgvDate.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.Column1,
this.Column2,
this.Column3,
this.Column4,
this.Column5,
this.Column6,
this.Column7});
this.dgvDate.Location = new System.Drawing.Point(12, 49);
this.dgvDate.Name = "dgvDate";
this.dgvDate.ReadOnly = true;
this.dgvDate.RowTemplate.Height = 23;
this.dgvDate.Size = new System.Drawing.Size(787, 375);
this.dgvDate.TabIndex = 2;
this.dgvDate.CellEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.dgvDate_CellEnter);
//
// rtbInfo
//
this.rtbInfo.Location = new System.Drawing.Point(12, 439);
this.rtbInfo.Name = "rtbInfo";
this.rtbInfo.Size = new System.Drawing.Size(787, 239);
this.rtbInfo.TabIndex = 3;
this.rtbInfo.Text = "";
//
// Column1
//
this.Column1.HeaderText = "星期日";
this.Column1.Name = "Column1";
this.Column1.ReadOnly = true;
//
// Column2
//
this.Column2.HeaderText = "星期一";
this.Column2.Name = "Column2";
this.Column2.ReadOnly = true;
//
// Column3
//
this.Column3.HeaderText = "星期二";
this.Column3.Name = "Column3";
this.Column3.ReadOnly = true;
//
// Column4
//
this.Column4.HeaderText = "星期三";
this.Column4.Name = "Column4";
this.Column4.ReadOnly = true;
//
// Column5
//
this.Column5.HeaderText = "星期四";
this.Column5.Name = "Column5";
this.Column5.ReadOnly = true;
//
// Column6
//
this.Column6.HeaderText = "星期五";
this.Column6.Name = "Column6";
this.Column6.ReadOnly = true;
//
// Column7
//
this.Column7.HeaderText = "星期六";
this.Column7.Name = "Column7";
this.Column7.ReadOnly = true;
//
// FormCustomDate
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(819, 708);
this.Controls.Add(this.rtbInfo);
this.Controls.Add(this.dgvDate);
this.Controls.Add(this.cboMonth);
this.Controls.Add(this.cboYear);
this.Name = "FormCustomDate";
this.Text = "自制日历-显示农历";
this.Load += new System.EventHandler(this.FormCustomDate_Load);
((System.ComponentModel.ISupportInitialize)(this.dgvDate)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ComboBox cboYear;
private System.Windows.Forms.ComboBox cboMonth;
private System.Windows.Forms.DataGridView dgvDate;
private System.Windows.Forms.RichTextBox rtbInfo;
private System.Windows.Forms.DataGridViewTextBoxColumn Column1;
private System.Windows.Forms.DataGridViewTextBoxColumn Column2;
private System.Windows.Forms.DataGridViewTextBoxColumn Column3;
private System.Windows.Forms.DataGridViewTextBoxColumn Column4;
private System.Windows.Forms.DataGridViewTextBoxColumn Column5;
private System.Windows.Forms.DataGridViewTextBoxColumn Column6;
private System.Windows.Forms.DataGridViewTextBoxColumn Column7;
}
}
三、新建类文件ChinaDate,用于显示中国农历描述以及节日信息:
ChinaDate.cs源程序如下:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CustomCalendarDemo
{
/// <summary>
/// 获取中国农历信息,
/// 关键类:ChineseLunisolarCalendar
/// </summary>
public static class ChinaDate
{
private static ChineseLunisolarCalendar china = new ChineseLunisolarCalendar();
private static Hashtable gHoliday = new Hashtable();
private static Hashtable nHoliday = new Hashtable();
private static string[] JQ = { "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "冬至" };
private static int[] JQData = { 0, 21208, 43467, 63836, 85337, 107014, 128867, 150921, 173149, 195551, 218072, 240693, 263343, 285989, 308563, 331033, 353350, 375494, 397447, 419210, 440795, 462224, 483532, 504758 };
static ChinaDate()
{
//公历节日
gHoliday.Add("0101", "元旦");
gHoliday.Add("0214", "情人节");
gHoliday.Add("0305", "雷锋日");
gHoliday.Add("0308", "妇女节");
gHoliday.Add("0312", "植树节");
gHoliday.Add("0315", "消费者权益日");
gHoliday.Add("0401", "愚人节");
gHoliday.Add("0501", "劳动节");
gHoliday.Add("0504", "青年节");
gHoliday.Add("0601", "儿童节");
gHoliday.Add("0701", "建党节");
gHoliday.Add("0801", "建军节");
gHoliday.Add("0910", "教师节");
gHoliday.Add("0918", "九一八纪念日");
gHoliday.Add("0930", "烈士纪念日");
gHoliday.Add("1001", "国庆节");
gHoliday.Add("1213", "国家公祭日");
//gHoliday.Add("1224", "平安夜");
gHoliday.Add("1225", "圣诞节");
//农历节日
nHoliday.Add("0101", "春节");
nHoliday.Add("0115", "元宵节");
nHoliday.Add("0505", "端午节");
nHoliday.Add("0815", "中秋节");
nHoliday.Add("0909", "重阳节");
nHoliday.Add("1208", "腊八节");
}
/// <summary>
/// 获取农历
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
public static string GetChinaDate(DateTime dt)
{
if (dt > china.MaxSupportedDateTime || dt < china.MinSupportedDateTime)
{
//日期范围:1901 年 2 月 19 日 - 2101 年 1 月 28 日
throw new Exception(string.Format("日期超出范围!必须在{0}到{1}之间!", china.MinSupportedDateTime.ToString("yyyy-MM-dd"), china.MaxSupportedDateTime.ToString("yyyy-MM-dd")));
}
string str = string.Format("{0}{1}{2}", GetYear(dt), GetMonth(dt), GetDay(dt));
string strJQ = GetSolarTerm(dt);
if (strJQ != "")
{
str += " (" + strJQ + ")";
}
string strHoliday = GetHoliday(dt);
if (strHoliday != "")
{
str += " " + strHoliday;
}
string strChinaHoliday = GetChinaHoliday(dt);
if (strChinaHoliday != "")
{
str += " " + strChinaHoliday;
}
return str;
}
/// <summary>
/// 获取农历年份
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
public static string GetYear(DateTime dt)
{
int yearIndex = china.GetSexagenaryYear(dt);
string yearTG = " 甲乙丙丁戊己庚辛壬癸";
string yearDZ = " 子丑寅卯辰巳午未申酉戌亥";
string yearSX = " 鼠牛虎兔龙蛇马羊猴鸡狗猪";
int year = china.GetYear(dt);
int yTG = china.GetCelestialStem(yearIndex);
int yDZ = china.GetTerrestrialBranch(yearIndex);
string str = string.Format("生肖:【{0}】\n{1}{2}年", yearSX[yDZ], yearTG[yTG], yearDZ[yDZ]);
return str;
}
/// <summary>
/// 获取农历月份
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
public static string GetMonth(DateTime dt)
{
int year = china.GetYear(dt);
int iMonth = china.GetMonth(dt);
int leapMonth = china.GetLeapMonth(year);
bool isLeapMonth = iMonth == leapMonth;
if (leapMonth != 0 && iMonth == leapMonth)
{
iMonth--;
}
string szText = "正二三四五六七八九十";
string strMonth = isLeapMonth ? "闰" : "";
if (iMonth <= 10)
{
strMonth += szText.Substring(iMonth - 1, 1);
}
else if (iMonth == 11)
{
strMonth += "十一";
}
else
{
strMonth += "腊";
}
return strMonth + "月";
}
/// <summary>
/// 获取农历日期
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
public static string GetDay(DateTime dt)
{
int iDay = china.GetDayOfMonth(dt);
string szText1 = "初十廿三";
string szText2 = "一二三四五六七八九十";
string strDay;
if (iDay == 20)
{
strDay = "二十";
}
else if (iDay == 30)
{
strDay = "三十";
}
else
{
strDay = szText1.Substring((iDay - 1) / 10, 1);
strDay = strDay + szText2.Substring((iDay - 1) % 10, 1);
}
return strDay;
}
/// <summary>
/// 获取节气
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
public static string GetSolarTerm(DateTime dt)
{
DateTime dtBase = new DateTime(1900, 1, 6, 2, 5, 0);
DateTime dtNew;
double num;
int y;
string strReturn = "";
y = dt.Year;
for (int i = 1; i <= 24; i++)
{
num = 525948.76 * (y - 1900) + JQData[i - 1];
dtNew = dtBase.AddMinutes(num);
if (dtNew.DayOfYear == dt.DayOfYear)
{
strReturn = JQ[i - 1];
}
}
return strReturn;
}
/// <summary>
/// 获取公历节日
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
public static string GetHoliday(DateTime dt)
{
string strReturn = "";
object g = gHoliday[dt.Month.ToString("00") + dt.Day.ToString("00")];
if (g != null)
{
strReturn = g.ToString();
}
return strReturn;
}
/// <summary>
/// 获取农历节日
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
public static string GetChinaHoliday(DateTime dt)
{
string strReturn = "";
int year = china.GetYear(dt);
int iMonth = china.GetMonth(dt);
int leapMonth = china.GetLeapMonth(year);
int iDay = china.GetDayOfMonth(dt);
if (china.GetDayOfYear(dt) == china.GetDaysInYear(year))
{
strReturn = "除夕";
}
else if (leapMonth != iMonth)
{
if (leapMonth != 0 && iMonth == leapMonth)
{
iMonth--;
}
object n = nHoliday[iMonth.ToString("00") + iDay.ToString("00")];
if (n != null)
{
if (strReturn == "")
{
strReturn = n.ToString();
}
else
{
strReturn += " " + n.ToString();
}
}
}
return strReturn;
}
}
}
四、窗体FormCustomDate(FormCustomDate.cs)的源程序如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CustomCalendarDemo
{
public partial class FormCustomDate : Form
{
//是否激活下拉框选择内容的改变事件全部加载基本内容后再激活
bool enabledSelectedEvent = false;
public FormCustomDate()
{
InitializeComponent();
rtbInfo.ReadOnly = true;
}
/// <summary>
/// 初始化数据设置年的范围为~2099年之间
/// </summary>
private void InitialData()
{
//年
DataTable dt = new DataTable("XX");
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Name", typeof(string));
for (int i = 1980; i < 2100; i++)
{
dt.Rows.Add(i, i + "年");
}
cboYear.DataSource = dt;
cboYear.DisplayMember = "Name";
cboYear.ValueMember = "ID";
//月
DataTable dtMonth = dt.Clone();
dtMonth.Rows.Add(1, "一月");
dtMonth.Rows.Add(2, "二月");
dtMonth.Rows.Add(3, "三月");
dtMonth.Rows.Add(4, "四月");
dtMonth.Rows.Add(5, "五月");
dtMonth.Rows.Add(6, "六月");
dtMonth.Rows.Add(7, "七月");
dtMonth.Rows.Add(8, "八月");
dtMonth.Rows.Add(9, "九月");
dtMonth.Rows.Add(10, "十月");
dtMonth.Rows.Add(11, "十一月");
dtMonth.Rows.Add(12, "十二月");
cboMonth.DataSource = dtMonth;
cboMonth.DisplayMember = "Name";
cboMonth.ValueMember = "ID";
}
/// <summary>
/// 显示某年某月的日历
/// </summary>
/// <param name="year"></param>
/// <param name="month"></param>
private void DisplayDate(int year, int month)
{
dgvDate.Rows.Clear();
DateTime firstDay = new DateTime(year, month, 1);
int columnIndex = (int)firstDay.DayOfWeek;
int maxDay = GetMaxDay(year, month);
//某月的第一天的星期数对应列的索引即当月天数需要额外增加columnIndex
//当月总天数设定为:columnIndex+maxDay。总分页数:(x+(n-1))/n 其中n=7
//表格共有行数:(columnIndex+maxDay+6)/7 取整
int day = 1;
for (int i = 0; i < (columnIndex + maxDay + 6) / 7; i++)
{
int index = dgvDate.Rows.Add();
for (int j = 0; j < 7; j++)
{
if (i == 0) //第一行从对应的星期开始填写
{
if (j >= columnIndex)
{
dgvDate[j, index].Value = day;
day++;
}
}
else
{
dgvDate[j, index].Value = day;
day++;
if (day > maxDay)
{
break;
}
}
}
}
}
/// <summary>
/// 获得某年某月有多少天
/// </summary>
/// <param name="year"></param>
/// <param name="month"></param>
/// <returns></returns>
private int GetMaxDay(int year, int month)
{
bool isLeapYear = DateTime.IsLeapYear(year);
switch (month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return 31;
case 4:
case 6:
case 9:
case 11:
return 30;
case 2:
return isLeapYear ? 29 : 28;
default:
return 0;
}
}
/// <summary>
/// 获得星期的中文描述
/// </summary>
/// <param name="week"></param>
/// <returns></returns>
private string GetWeekDay(DayOfWeek week)
{
switch (week)
{
case DayOfWeek.Sunday:
return "星期日";
case DayOfWeek.Monday:
return "星期一";
case DayOfWeek.Tuesday:
return "星期二";
case DayOfWeek.Wednesday:
return "星期三";
case DayOfWeek.Thursday:
return "星期四";
case DayOfWeek.Friday:
return "星期五";
case DayOfWeek.Saturday:
return "星期六";
default:
return "";
}
}
private void FormCustomDate_Load(object sender, EventArgs e)
{
//只能选择一个单元格、列不可排序
dgvDate.MultiSelect = false;
for (int i = 0; i < 7; i++)
{
dgvDate.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable;
}
InitialData();
//默认为当前年月
DateTime currentDate = DateTime.Now;
for (int i = 0; i < cboYear.Items.Count; i++)
{
DataRowView drv = cboYear.Items[i] as DataRowView;
if (Convert.ToInt32(drv.Row["ID"]) == currentDate.Year)
{
cboYear.SelectedIndex = i;
break;
}
}
for (int i = 0; i < cboMonth.Items.Count; i++)
{
DataRowView drv = cboMonth.Items[i] as DataRowView;
if (Convert.ToInt32(drv.Row["ID"]) == currentDate.Month)
{
cboMonth.SelectedIndex = i;
break;
}
}
DisplayDate(currentDate.Year, currentDate.Month);
for (int i = 0; i < dgvDate.Rows.Count; i++)
{
bool isBreak = false;
for (int j = 0; j < 7; j++)
{
if (Convert.ToString(dgvDate[j, i].Value) == currentDate.Day.ToString())
{
isBreak = true;
dgvDate[j, i].Selected = true;
break;
}
}
if (isBreak)
{
break;
}
}
//D2: 格式化为位数字不足位则前面补0
DisplayContents(currentDate);
enabledSelectedEvent = true;
}
private void DisplayContents(DateTime currentDate)
{
//显示 癸卯年闰二月初五
rtbInfo.Text = string.Format("当前日期:{0}年{1:D2}月{2:D2}日 {3}\n{4}",
currentDate.Year, currentDate.Month, currentDate.Day,
GetWeekDay(currentDate.DayOfWeek), ChinaDate.GetChinaDate(currentDate));
}
private void cboYear_SelectedIndexChanged(object sender, EventArgs e)
{
if (enabledSelectedEvent)
{
DisplayDate(Convert.ToInt32(cboYear.SelectedValue), Convert.ToInt32(cboMonth.SelectedValue));
}
}
private void cboMonth_SelectedIndexChanged(object sender, EventArgs e)
{
if (enabledSelectedEvent)
{
DisplayDate(Convert.ToInt32(cboYear.SelectedValue), Convert.ToInt32(cboMonth.SelectedValue));
}
}
private void dgvDate_CellEnter(object sender, DataGridViewCellEventArgs e)
{
if (dgvDate.SelectedCells.Count < 1)
return;
object day = dgvDate.SelectedCells[0].Value;
if (Convert.ToInt32(day) > 0)
{
DateTime currentDate = new DateTime(Convert.ToInt32(cboYear.SelectedValue),
Convert.ToInt32(cboMonth.SelectedValue), Convert.ToInt32(day));
DisplayContents(currentDate);
}
else //没有选择日历的单元格
{
rtbInfo.Text = "";
}
}
}
}
五、程序运行如图: