محاسبه اختلاف دو تاریخ

در این بخش به شما نحوه ایجاد یک ماشین حساب که اختلاف بین دو تاریخ را محاسبه می‌کند آموزش داده می‌شود. برنامه از متدهای System.DateTime و System.TimeSpan استفاده می‌کند این آموزش همچنین مهارت شما را در استفاده از رویدادها و کنترل ComboBox افزایش می‌دهد. یک برنامه ویندوزی ایجاد کنیدو نام آن را TimeDifferenceCalculator بگذارید. سپس مانند شکل زیر کنترلهای لازم را بر روی آن قرار دهید و مرتب کنید.
time-difference-calculator-02-02-11-01
به صورت اختیاری می‌توانید خاصیت Text فرم را تغییر داده و همچنین خاصیت FormBorderStyle را به FixedSingle تغییر دهید تا اندازه فرم ثابت بماند. خاصیت Name کنترل‌های شماره گذاری شده را مطابق جدول زیر تغییر دهید.
time-difference-calculator-02-02-11-02

شماره نام
1 comboBeginDateMonth
2 comboBeginDateDay
3 comboBeginDateYear
4 comboEndDateMonth
5 comboEndDateDay
6 comboEndDateYear
7 labelResult
8 buttonCalculate

خاصیت Text کنترل labelResult را پاک کنید تا نتیجه محاسبه در آن قرار بگیرد. بر روی فرم (نه کنترل‌ها) دو بار کلیک کنید تا یک کنترل کننده رویداد برای خاصیت Load فرم ایجاد شود. سپس کد زیر را به آن اضافه کنید.

private void Form1_Load(object sender, EventArgs e)
{
    //تعریف ماه‌ها
    string[] months = 
    {
        "January", "February", "March", "April",
        "May", "June", "July", "August",
        "September", "October", "November", "December"
    };

    //پر کردن کمبوباکس ها با ماه‌ها
    for (int i = 0; i < 12; i++)
    {
        comboBeginDateMonth.Items.Add(months[i]);
        comboEndDateMonth.Items.Add(months[i]);
    }

    //قرار دادن ماه ژانویه به عنوان ماه پیشفرض
    comboBeginDateMonth.SelectedIndex = 0;
    comboEndDateMonth.SelectedIndex = 0;

    //پر کردن کمبوباکس ها با سال
    for (int i = 1; i <= DateTime.Now.Year; i++)
    {
        comboBeginDateYear.Items.Add(String.Format("{0:0000}", i));
        comboEndDateYear.Items.Add(String.Format("{0:0000}", i));
    }

    //پیشفرض قرار دادن سال 2000
    comboBeginDateYear.SelectedIndex = 1999;
    comboEndDateYear.SelectedIndex = 1999;

    //پر کردن کمبوباکس ها با روز
    FillDays(comboBeginDateDay, "Begin");
    FillDays(comboEndDateDay, "End");

    //اضافه کردن کنترل کننده رویداد
    comboBeginDateMonth.SelectedIndexChanged += new EventHandler(RecalculateDays);
    comboBeginDateYear.SelectedIndexChanged += new EventHandler(RecalculateDays);
    comboEndDateMonth.SelectedIndexChanged += new EventHandler(RecalculateDays);
    comboEndDateYear.SelectedIndexChanged += new EventHandler(RecalculateDays);
}

اولین چیزی که ما ایجاد می‌کنیم آرایه‌ای رشته‌ای است که 12 ماه سال را در خود جای می‌دهد. سپس با استفاده از حلقه for ماه‌ها را به دو کمبوباکس (combo boxes) برای نشان دادن آنها (ماه‌ها) اضافه می‌کنیم. به وسیله متد Add خاصیت Item کلاس ComboBox این کار را انجام می‌دهیم. سپس خاصیت SelectedIndex دو کمبوباکس را به عدد صفر تغییر می‌دهیم که نشان دهنده اولین آیتم یعنی ماه ژانویه است. نکته مهم این است که چون اندیس‌ها در کمبو باکس‌ها از صفر شروع می‌شود در نتیجه شمارش نیز از صفر آغاز می‌شود.

سپس کمبو باکس‌هایی که قرار است سال‌ها را نمایش دهند را از عدد 1 تا سال جاری پر می‌کنیم. برای دسترسی به سال جاری از خاصیت Year خاصیت Now کلاس DateTime استفاده می‌کنیم. خاصیت Now نشان دهنده ساعت و تاریخ جاری است. همه سال‌ها را برای نمایش به کمبوباکس ها اضافه می‌کنیم. برای قالب بندی سال‌ها از 4 صفر استفاده می‌کنیم بنابراین همه سال‌ها 4 رقمی نشان داده می‌شوند. با اختصاص مقدار 1999 به خاصیت SelectedIndex دو کمبوباکس مسئول نمایش سال، سال 2000 را سال مبنا قرار می‌دهیم. به خاطر داشته باشید که SelectedIndex از صفر شروع می‌شود در نتیجه برای نمایش سال 2000 باید اندیس آن 1999 باشد.

به این نکته توجه کنید که می‌توانیم به قسمت طراحی فرم رفته و بر روی کمبوباکس مورد نظر کلیک کنیم سپس با استفاده خاصیت Items پیدا کنیم. با کلیک بر رو دکمه مقابل این خاصیت که دارای سه نقطه است صفحه‌ای باز می‌شود که بوسیله آن می‌توانیم هر آیتمی به کمبوباکس اضافه کنیم. اما این کار قطعاً برای شما خسته کننده است چون قرار است که 2000 یا تعداد بیشتری مقدار را به آن اضافه کنیم. برای راحتی کار می‌توانیم از طریق کدنویسی این کار را انجام دهیم.

متد FillDays که قبلاً ایجاد کرده‌ایم کمبوباکس ها را برای نمایش روز پر می‌کند. ولی تعداد روزها در کمبوباکس‌ها برابر است. مثلاً کمبوباکس های مسئول نشان دادن روزها همگی دارای 30 روز می‌باشند، در اینجا به مشکل بر می‌خوریم چون بعضی از ماه‌ها 31 روزه هستند و سال کبیسه هم وجود دارد. در 4 خط آخر کد یک کنترل کننده رویداد به رویداد SelectedIndexChanged هر کمبوباکس اضافه کرده‌ایم. این رویداد زمانی آزاد می‌شود که یک اندیس انتخاب شود و یا یک آیتم تغییر کند.

یک کنترل کننده رویداد ایجاد کرده‌ایم، که بین 4 کنترل تقسیم می‌شود. لازم است که این کنترل کننده رویداد را به کمبوباکس هایی که مسئول نگداری ماه‌ها و سال‌ها هستند اضافه کنیم، بنابر این زمانی که کاربر یک سال یا ماه را تغییر می‌دهد، آیتم‌های داخل کمبو باکس‌های مسئول نگهداری روز به طور خودکار به روز (آپدیت) می‌شوند. کنترل کننده‌های رویداد را در آخر کدها قرار می‌دهیم، چون ما خاصیت SelectedIndex کمبوباکس ها را تغییر می‌دهیم که این کار باعث آزاد شدن رویداد و اجرای کنترل کننده‌های رویدادی می‌شود که باعث خالی شدن کمبوباکس ها می‌شوند. این کار باعث به وجود آمدن یک خطا می‌شود. اجازه دهید که یک متد FillDays ایجاد کنیم. این متد باعث پر شدن روزهای یک کمبوباکس مشخص می‌شود. این متد یک کمبوباکس را به عنوان پارامتر آرگومان قبول می‌کند و دومین پارامتر آن یک رشته‌ای است که نشان می‌دهد کدام یک از کمبوباکس های comboBeginDateDay یا comboEndDataDay به روز شده‌اند.

private void FillDays(ComboBox comboBox, string tag)
{
    int selectedMonth;
    int selectedYear;

    if (tag == "Begin")
    {
        selectedMonth = comboBeginDateMonth.SelectedIndex + 1;
        selectedYear = comboBeginDateYear.SelectedIndex + 1;
    }
    else
    {
        selectedMonth = comboEndDateMonth.SelectedIndex + 1;
        selectedYear = comboEndDateYear.SelectedIndex + 1;
    }

    int maxDay = DateTime.DaysInMonth(selectedYear, selectedMonth);

    comboBox.Items.Clear();

    for (int i = 1; i <= maxDay; i++)
    {
        comboBox.Items.Add(i);
    }

    comboBox.SelectedIndex = 0;
}

ابتدا با استفاده از پارامتر tag مشخص می‌کنیم کدام یک از کمبوباکس های month و year مقادیر را دریافت می‌کنند. سپس خاصیت SelectedIndex آن‌ها را با عدد 1 جمع کرده و برابر متغیرهایی قرار می‌دهیم که به وسیله متد DaysInMonth مورد استفاده قرار می‌گیرند. سپس از متد استاتیک DaysInMonth کلاس DateTime برای چک کردن روزهای ماه‌های سال‌های خاص (کبیسه) استفاده می‌کنیم. برای آپدیت کردن کمبوباکس ابتدا آیتم‌ها را حذف می‌کنیم. تعداد روزها را با خواندن روزها با استفاده از یک حلقه for بروز می‌کنیم. سر انجام مقدار خاصیت SelectedIndex ازکامبو باکس را برابر 0 قرار می‌دهیم تا مقدار پیشفرض آن برابر 1 شود. سازنده Form1 را پیدا کرده و کد پر رنگ شده زیر را به آن اضافه کنید.

public Form1()
{
    InitializeComponent();

    comboBeginDateMonth.Tag = "Begin";
    comboBeginDateYear.Tag = "Begin";
    comboEndDateMonth.Tag = "End";
    comboEndDateYear.Tag = "End";
}

سپس آن مقادیر را به خصوصیت Tag نسبت می‌دهیم تا کامبوباکس درست را برای بروزرسانی به متد RecalculateDays ارسال کنیم.

private void RecalculateDays(object sender, EventArgs e)
{
    if ((sender as ComboBox).Tag.ToString() == "Begin")
        FillDays(comboBeginDateDay, "Begin");
    else
        FillDays(comboEndDateDay, "End");
}

به این نکته توجه نمایید که این متد به عنوان کنترل کننده رویداد برای رویداد SelectedIndexChanged انتخاب شده است، نماینده این رویداد متدی را می‌پذیرد که 2 پارامتر از نوع object و EventArgs داشته باشد. متد شامل یک دستور if است که کنترل فعال کننده متد را به نوع کامبو باکس تبدیل می‌کند تا از خصوصیت Tag آن استفاده کند. ما نتیجه را با رشته “Begin” مقایسه می‌کنیم بنابراین برنامه تشخیص می‌دهد که کمبوباکس به روز شده است. به قسمت طراحی برمی گردیم و بر روی buttonCalculate دو بار کلیک می‌کنیم تا یک کنترل کننده رویداد برای رویداد کلیک ایجاد شود. کد زیر را اضافه می‌کنیم.

private void buttonCalculate_Click(object sender, EventArgs e)
{
    DateTime beginDate = new DateTime(
        comboBeginDateYear.SelectedIndex + 1,
        comboBeginDateMonth.SelectedIndex + 1,
        comboBeginDateDay.SelectedIndex + 1);

    DateTime endDate = new DateTime(
        comboEndDateYear.SelectedIndex + 1,
        comboEndDateMonth.SelectedIndex + 1,
        comboEndDateDay.SelectedIndex + 1);

    TimeSpan difference = endDate.Subtract(beginDate);

    labelResult.Text = String.Format("{0} Days", difference.Days);
}

بر روی دکمه کلیک کرده، تاریخ‌های شروع و پایان به درستی در کامبوباکس‌ها نمایش داده می‌شوند. سپس تفاوت را با استفاده از متد Subtract محاسبه می‌کنیم. این متد یک شیء از TimeSpan را برگشت می‌دهد. در آخر هم تفاوت دو تاریخ را در کنترل labelResult نمایش می‌دهیم. برنامه قابلیت بهبود بیشتری را هم دارا می‌باشد. به عنوان مثال شما می‌توانید تعداد بیشتری کمبو باکس جهت یافتن اختلاف ساعت، دقیقه و ثانیه به برنامه اضافه کنید. همچنین می‌توانید تفاوت بین ماهها و سال‌ها را نیز محاسبه کنید. از متد IsLeapYear هم می‌توان برای تشخیص سال‌های کبیسه استفاده نمود.