PROGRAMOWANIE – PRZYKŁADY
IDE C++ WinBGI C# Wpadki

Przykład C#

Dzień tygodnia Algorytmy Klasa obliczeń kalendarzowych w C# Przeciążanie metod Komentarze XML i podpowiedzi składni Programy w Visual C# Poprzedni przykład Następny przykład Program w C++ Kontakt

Dzień tygodnia

Program ma wczytać z konsoli datę, np. trzy doda­tnie liczby całko­wite d, mr określa­jące numer dnia, miesiąca i roku, a nastę­pnie wypisać, jaki dzień tygo­dnia i który z kolei dzień w roku ta data przed­stawia. Rozwią­zanie zadania wymaga znajo­mości zasady określa­nia roku przestę­pnego w obowią­zującym obecnie kalen­darzu grego­riańskim:

Rok jest przestępny, gdy jego numer dzieli się przez 4, ale nie dzieli się przez 100, bądź też, gdy dzieli się przez 400.

Według niej nie wszystkie lata, których numer jest podzielny przez 4, są prze­stępne. Na przy­kład rok 1900 był zwykły, pomimo że lata 1896 i 1904 były przestę­pne, ale rok rok 2000 był prze­stępny. W poprze­dnim kalen­darzu, juliań­skim, lata prze­stępne liczone były co 4 lata, skutkiem czego spóźniał się on względem kalen­darza astrono­micznego o 1 dzień na 128 lat. Kalen­darz grego­riański został wprowa­dzony 15 paździe­rnika 1582 roku przez papieża Grze­gorza XIII w celu znie­sienia tego opóźnienia. Różnica między cyklem przyro­dniczym a kalen­darzem juliań­skim, która wyno­siła wtedy 10 dni, została zniwe­lowana tak, że po dniu 4 paździe­rnika (czwartek) nastąpił 15 paździe­rnika (piątek). Obecnie różnica ta wynosi około dwóch tygodni. Bitwa pod Grun­waldem, jedna z najwię­kszych bitew w historii średnio­wiecznej Europy, stoczona była według ówcze­snego kalen­darza 15 lipca 1410 roku, a według obecnego 9 dni później.

Warto przy okazji wspomnieć, że Polska była jednym z czte­rech krajów, które od razu przyjęły nowy kalen­darz (czasy Anny Jagiel­lonki i Ste­fana Bato­rego). Pozos­tała trójka to: Włochy, Hiszpania i Portu­galia. Później zrobiły to: Francja (20 gru­dnia 1582), Belgia i Holandia (1582–1583, 1700–1701, różne regiony zależnie od wyzna­nia), Austria (1583), Niemcy (1583–1585, 1700), Szwaj­caria (1583–1584, 1597, 1701), Węgry (1587), Prusy (1610), Dania i Norwegia (1700), Wielka Brytania i Irlandia (1752), Szwecja i Finlandia (1753). Niektóre kraje uznały reformę kalen­darza dopiero w ubiegłym stuleciu: Bułgaria (1916), Rosja (1918), Jugo­sławia i Rumunia (1919), Grecja (1924), Turcja (1927).

Data wprowa­dzenia kalen­darza gregoriań­skiego znalazła nawet reper­kusje w oprogra­mowaniu kompu­terów, pomimo że poja­wiły się one znacznie później. Na przy­kład w kompo­nentach kalenda­rzowych Delphi i C++ Builder wrze­sień 1752 roku ma tylko 19 dni, co stanowi ślad później­szego wprowa­dzenia kalen­darza gregoriań­skiego przez Wielką Brytanię (większość obecnych tery­toriów USA była wówczas pod pano­waniem brytyj­skim). Z kolei w środo­wisku Visual C# metoda DayOfWeek (dzień tygodnia) klasy DateTime (data i czas) błędnie podaje, że 4 paździer­nika 1582 roku przy­padał w ponie­działek.

Algorytmy

Liczby dni miesięcy kalendarza są ustalone według niewy­godnego dla obli­czeń sche­matu, a w przy­padku lutego są różne dla lat zwykłych i prze­stępnych (28 i 29), dlatego najwygo­dniej je umieścić w tablicy dwuwy­miarowej:

int[,] n = {{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
            {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};

Jej dwa 13-elementowe wiersze są inicjali­zowane zerem i liczbami dni miesięcy dla roku zwykłego i przestę­pnego. Doda­tkowy element na początku wierszy ułatwia natu­ralną nume­rację miesięcy od 1 do 12. Gdyby wiersze były 12-elemen­towe (bez dodatkowego zera), należa­łoby miesiące nume­rować od 0 do 11. Przekształ­cenie daty reprezen­towanej przez liczby całko­wite d, mr na numer dnia w roku (liczbę dni od początku roku) sprowadza się do dodania do d sumy dni wszys­tkich miesięcy roku r poprzedza­jących miesiąc m:

int Ndr(int d, int m, int r)
{
    int p = ((r % 4 == 0 && r % 100 != 0) || r % 400 == 0) ? 1 : 0;
    while (--m > 0)
        d += n[p, m];
    return d;
}

Zgodnie z suge­stią kompi­latora Visual C# nazwy metod będziemy pisać dużą literą (rozpoczy­nanie nazwy od małej litery nie jest błędem). W powyższej metodzie zmiennej p przypi­sana zostaje wartość 1, gdy rok r jest przestę­pny, albo 0, gdy jest zwykły. Użyto tu tzw. opera­tora warun­kowego, którego postać jest taka sama jak w językach C i C++:

wyrażenie_logiczne ? wyrażenie_1 : wyrażenie_2

Najpierw obliczane jest wyrażenie logiczne określające pewien warunek. Jeżeli ma ono wartość true (warunek speł­niony), wynikiem całego wyra­żenia jest wartość wyra­żenia po znaku ?. W prze­ciwnym razie, tj. gdy wyrażenie logiczne ma wartość false (warunek niespeł­niony), wynikiem całego wyra­żenia jest wartość wyra­żenia po znaku :. Opera­tor warun­kowy można oczywi­ście zastąpić instru­kcją if—else, która w rozpa­trywanym przypadku miałaby postać:

int p;
if ((r % 4 == 0 && r % 100 != 0) || r % 400 == 0)
    p = 1;
else
    p = 0;

Jeden z wielu algorytmów znajdowania dnia tygodnia dla podanej daty polega na obli­czeniu liczby dni, jaka dzieli tę datę od daty, dla której dzień tygo­dnia jest znany, a nastę­pnie wyko­naniu operacji modulo 7 i wybraniu tego dnia spośród siedmiu, który pasuje do otrzy­manej reszty. Przykła­dowo, od 6 stycznia 1983 roku, który to dzień przypadał w czwartek, do 12 wrze­śnia 2018 roku upłynęło 13033 dni. Liczba ta po zwiększeniu o 4 (czwartek, więc przesu­nięcie o 4 dni) daje przy dzieleniu przez 7 resztę 3. Zatem dzień określony przez drugą datę przypada w środę.

Jest oczywiste, że taki algorytm wymaga pętli i szeregu nieco kłopo­tliwych rozstrzy­gnięć. O wiele prostsze rozwią­zanie polega na wykorzy­staniu zaczer­pniętego z amerykań­skiego czaso­pisma i nieco zmodyfi­kowanego wzoru:

w którym nawiasy kwadratowe oznaczają część całko­witą (kreska ułam­kowa odpo­wiada dzieleniu całko­witemu), mod oznacza resztę z dzielenia (modulo, opera­tor %), a liczby d, m, rw są okre­ślane następująco:

d numer dnia w miesiącu;
m przekształcony numer miesiąca: 1 – marzec, 2 – kwiecień, ..., 10 – grudzień, 11 – styczeń, 12 – luty;
r liczba reprezentowana przez dwie ostatnie cyfry pełnego numeru roku: danego – dla miesięcy od marca do grudnia, poprze­dniego – dla stycznia i lutego;
w liczba reprezentowana przez pozostałe (dwie początkowe) cyfry numeru roku.

Na przykład dla daty 12.09.2018 r. należy przyjąć: d = 12, m = 7, r = 18, w = 20, a dla daty 06.01.2000 r.: d = 6, m = 11, r = 99, w = 19. Obli­czona według wzoru wartość jest liczbą całko­witą od 0 do 6 reprezen­tującą dzień tygo­dnia: 0 – niedziela, 1 – ponie­działek, ..., 6 – sobota. Algorytm, który dla trzech liczb całkowitych d, mr reprezen­tujących datę oblicza liczbę całkowitą określa­jącą dzień tygo­dnia, który ta data przed­stawia, można zaprogra­mować nastę­pująco:

int Dtyg(int d, int m, int r)
{
    if (m > 2)         // Jeśli miesiąc późniejszy niż luty,
        m -= 2;        // zmniejsz jego numer o 2.
    else               // W przeciwnym przypadku
    {                  // (gdy styczeń lub luty)
        m += 10;       // zwiększ numer miesiąca o 10
        r--;           // i pomniejsz numer roku o 1.
    }
    int w = r / 100;
    r %= 100;
    return (d + (13*m - 1)/5 + r + r/4 + w/4 + 5*w) % 7;
}

Klasa obliczeń kalendarzowych w C#

Metody realizujące obliczenia doty­czące kalen­darza grego­riańskiego zgru­pujemy w klasę, którą będzie można wykorzy­stywać w różnych progra­mach. Najpierw tworzymy projekt prostego programu o nazwie Dzien1 wczytu­jącego trzy liczby całko­wite d, mr reprezen­tujące datę (dzień, miesiąc i rok). Nastę­pnie do proje­ktu programu dodajemy nowy element – klasę o nazwie Kalend, korzy­stając z pole­cenia Projekt Dodaj klasę... lub Projekt Dodaj nowy element... (w drugim przy­padku w oknie kreatora wybieramy z listy dostę­pnych elementów pozycję Klasa). Po wpro­wadzeniu nazwy klasy zamykamy okno przyci­skiem Dodaj (rys.).

W tym momencie w folderze projektu utworzony został plik źródłowy o nazwie Kalend.cs zawiera­jący pustą defi­nicję nowej klasy w prze­strzeni nazw Dzien1:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dzien1
{
    class Kalend
    {
    }
}

Klasa ma być używana w innych programach, toteż warto zmienić nazwę jej prze­strzeni na bardziej suge­stywną, np. na Kalendarz.Greg (kalen­darz grego­riański, prze­strzeń Greg zagnie­żdżona w prze­strzeni Kalendarz). Zmiana ta wymaga dodania w pliku Dzien1.cs dyrektywy using włącza­jącej do pro­gramu nową prze­strzeń. Z kolei w pliku Kalend.cs można usunąć wszystkie dyrektywy using, gdyż żadna z włą­czanych przez nie prze­strzeni nie będzie w klasie Kalend potrzebna. Na początku kodu źródło­wego klasy umieszczamy, podobnie jak w pliku nagłów­kowym modułu C++, komen­tarz informu­jący o dostę­pnych w niej metodach, a wewnątrz klasy defi­nicje tych metod i pole określa­jące liczby dni poszcze­gólnych miesięcy lat zwykłych i prze­stępnych:

// Kalend - klasa obliczeń kalendarza gregoriańskiego, wersja 1
// ----------------------------------------------------------------------
// Przest - sprawdza, czy rok r jest przestępny (false - nie, true - tak)
// Dmax   - zwraca liczbę dni miesiąca m roku r
// Ndr    - oblicza, który z kolei dzień w roku przedstawia data d, m, r
// Dtyg   - oblicza, jaki dzień tygodnia przedstawia data d, m, r
//          (0 - niedziela, 1 - poniedziałek, ..., 6 - sobota)
// ----------------------------------------------------------------------
namespace Kalendarz.Greg
{
    static public class Kalend
    {
        static public bool Przest(int r)
        {
            return (r % 4 == 0 && r % 100 != 0) || r % 400 == 0;
        }

        static public int Dmax(int m, int r)
        {
            return n[Przest(r) ? 1 : 0, m];
        }

        static public int Ndr(int d, int m, int r)
        {
            int p = Przest(r) ? 1 : 0;
            while (--m > 0)
                d += n[p, m];
            return d;
        }

        static public int Dtyg(int d, int m, int r)
        {
            if (m > 2)
                m -= 2;
            else
            {
                m += 10;
                r--;
            }
            int w = r / 100;
            r %= 100;
            return (d + (13 * m - 1) / 5 + r + r / 4 + w / 4 + 5 * w) % 7;
        }

        static readonly int[,] n =
            {{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
             {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
    }
}

Zarówno klasa, jak i jej metody są publiczne, dzięki czemu użytko­wnik ma do nich dostęp spoza klasy (pole n jest prywatne, dostęp do niego jest możliwy tylko wewnątrz klasy). Wszy­stkie składowe klasy są staty­czne, można się więc do nich odwo­ływać bez uprze­dniego tworzenia obiektu (instan­cji) tej klasy. Kod źródłowy pierw­szej wersji programu korzysta­jącego z klasy Kalend może wyglądać nastę­pująco:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kalendarz.Greg;

namespace Dzien1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Dzień  : ");
            int d = Convert.ToInt32(Console.ReadLine().Trim());
            Console.Write("Miesiąc: ");
            int m = Convert.ToInt32(Console.ReadLine().Trim());
            Console.Write("Rok    : ");
            int r = Convert.ToInt32(Console.ReadLine().Trim());
            Console.WriteLine("{0}, {1} dzień roku.",
                    Nazwa[Kalend.Dtyg(d, m, r)], Kalend.Ndr(d, m, r));
        }

        static string[] Nazwa = {"Niedziela", "Poniedziałek", "Wtorek",
                                 "Środa", "Czwartek", "Piątek", "Sobota"};
    }
}

A oto przykładowe wyniki wykonania programu dla daty uchwa­lenia Konsty­tucji 3 Maja:

Przeciążanie metod

W języku C# mogą w danej klasie istnieć metody o tej samej nazwie, jeśli różnią się one liczbami argu­mentów lub ich typami. Ta bardzo użyte­czna i często spoty­kana technika progra­mowania nazywana jest przecią­żaniem lub przełado­wywaniem metod. Przykła­dami metod przecią­żonych są: metoda Substring klasy String (dwie wersje, jeden lub dwa argu­menty) i metoda Abs klasy Math (siedem wersji dla różnych typów argu­mentu).

Jeżeli dwie zerowe wartości elementów tablicy n będącej prywatnym polem klasy Kalend zastą­pimy liczbami 365 i 366, możemy rozbu­dować tę klasę o prostą metodę zwraca­jącą liczbę dni roku określo­nego w jej jedynym argu­mencie. Nowej metodzie możemy nadać nazwę Dmax – taką samą, jak istnie­jąca już dwuargu­mentowa metoda tej klasy zwraca­jąca liczbę dni miesiąca danego roku. Obie metody będą miały tę samą nazwę, ale różnić się będą inną liczbą argu­mentów. Chociaż liczbę dni roku można wyznaczyć za pomocą metody Ndr, określa­jąc w argu­mentach datę 31 grudnia tegoż roku, nowa metoda Dmax jest od Ndr wydaj­niejsza (brak pętli i jeden argu­ment zamiast trzech):

int Dmax(int r)
{
    return n[Przest(r) ? 1 : 0, 0];    // n[0,0] == 365, n[1,0] == 366
}

Ta nowa metoda może posłużyć do rozszerzenia klasy Kalend o kolejną metodę, która wyznacza liczbę dni, jaka pozostała do końca roku od dnia reprezen­towanego przez podaną datę:

int Kdr(int d, int m, int r)
{
    return Dmax(r) - Ndr(d, m, r);
}

Komentarze XML i podpowiedzi składni

Środowisko Visual C# umożliwia tworzenie tzw. komen­tarzy XML, które służą do opisy­wania kodu klas, ich metod, pól i właści­wości. Na podstawie takich komen­tarzy można generować dokumen­tację oprogra­mowania w formacie XML (tema­tyka pomi­nięta w niniej­szej witrynie interne­towej), a ponadto są one wykorzy­stywane przez system IntelliSence Visual C# do genero­wania podpo­wiedzi składni języka. Gdy w kodzie źródłowym nie ma komen­tarzy XML, wyświe­tlane przez system podpo­wiedzi są skrócone. Na przy­kład w trakcie pisania przedsta­wionego wyżej programu pojawiła się następu­jąca podpo­wiedź:

Jeśli natomiast klasę Kalend opatrzymy stosownymi komenta­rzami XML, podpo­wiedź systemu w tym samym miejscu kodu źródło­wego programu będzie pełniejsza:

Tworzenie komentarzy XML w środowisku Visual C# jest bardzo proste. Wystarczy bowiem bezpo­średnio nad danym elementem wprowa­dzić trzyzna­kowy ciąg ukośników ///, a na ekranie pojawi się szkielet komen­tarza złożonego ze znaczników XML, który należy uzupeł­nić. Na przykład powyższa podpo­wiedź pojawiła się w wyniku zamie­szczenia komen­tarza postaci:

/// <summary>
/// Oblicza, jaki dzień tygodnia przedstawia data
/// </summary>
/// <param name="d">numer dnia</param>
/// <param name="m">numer miesiąca</param>
/// <param name="r">numer roku</param>
/// <returns>0 - niedziela, 1 - poniedziałek, ..., 6 - sobota</returns>
static public int Dtyg(int d, int m, int r)
{
    ...     // Kod j.w.
}

W komentarzach dokumentacyjnych XML używa się m.in. następu­jących znaczników:

Oto kod źródłowy drugiej wersji klasy Kalend rozsze­rzonej o dwie omówione wyżej metody DmaxKdr oraz komen­tarze XML dostar­czające informacji wyświe­tlanych w podpo­wiedziach IntelliSence:

/// <summary>
/// Kalendarz gregoriański, wersja 2
/// </summary>
namespace Kalendarz.Greg
{
    /// <summary>
    /// Klasa obliczeń kalendarzowych
    /// </summary>
    static public class Kalend
    {
        /// <summary>
        /// Sprawdza, czy rok jest przestępny
        /// </summary>
        /// <param name="r">numer roku</param>
        /// <returns>false - zwykły, true - przestępny</returns>
        static public bool Przest(int r)
        {
            return (r % 4 == 0 && r % 100 != 0) || r % 400 == 0;
        }

        /// <summary>
        /// Zwraca liczbę dni roku
        /// </summary>
        /// <param name="r">numer roku</param>
        /// <returns>liczba dni roku</returns>
        static public int Dmax(int r)
        {
            return n[Przest(r) ? 1 : 0, 0];
        }

        /// <summary>
        /// Zwraca liczbę dni miesiąca
        /// </summary>
        /// <param name="m">numer miesiąca</param>
        /// <param name="r">numer roku</param>
        /// <returns>liczba dni miesiąca</returns>
        static public int Dmax(int m, int r)
        {
            return n[Przest(r) ? 1 : 0, m];
        }

        /// <summary>
        /// Oblicza, który z kolei dzień przedstawia data
        /// </summary>
        /// <param name="d">numer dnia</param>
        /// <param name="m">numer miesiąca</param>
        /// <param name="r">numer roku</param>
        /// <returns>numer dnia od początku roku</returns>
        static public int Ndr(int d, int m, int r)
        {
            int p = Przest(r) ? 1 : 0;
            while (--m > 0)
                d += n[p, m];
            return d;
        }

        /// <summary>
        /// Oblicza, ile dni pozostało do końca roku
        /// </summary>
        /// <param name="d">numer dnia</param>
        /// <param name="m">numer miesiąca</param>
        /// <param name="r">numer roku</param>
        /// <returns>liczba dni do końca roku</returns>
        static public int Kdr(int d, int m, int r)
        {
            return Dmax(r) - Ndr(d, m, r);
        }

        /// <summary>
        /// Oblicza, jaki dzień tygodnia przedstawia data
        /// </summary>
        /// <param name="d">numer dnia</param>
        /// <param name="m">numer miesiąca</param>
        /// <param name="r">numer roku</param>
        /// <returns>0 - niedziela, 1 - poniedziałek, ..., 6 - sobota</returns>
        static public int Dtyg(int d, int m, int r)
        {
            if (m > 2)
                m -= 2;
            else
            {
                m += 10;
                r--;
            }
            int w = r / 100;
            r %= 100;
            return (d + (13 * m - 1) / 5 + r + r / 4 + w / 4 + 5 * w) % 7;
        }

        /// <summary>
        /// Liczby dni miesięcy lat zwykłych i przestępnych
        /// </summary>
        static readonly int[,] n =
            {{365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
             {366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
    }
}

Programy w Visual C#

Zamiast trzech liczb całkowitych (numer dnia, miesiąca i roku) data jest zazwyczaj reprezen­towana za pomocą ciągu 10 znaków. W polskiej tradycji piśmien­niczej ciąg taki ma format DD.MM.RRRR, np. data 24 września 2018 roku jest zapisy­wana jako 24.09.2018. Spoty­kane są również formaty RRRR-MM-DD (standard ISO popu­larny również w Polsce) i MM/DD/RRRR (format amery­kański), np. 2018-09-24 i 09/24/2018. W pro­gramie wczy­tującym datę w dowolnym z wymie­nionych formatów i wyzna­czającym w oparciu o klasę Kalend, jaki dzień tygo­dnia i który z kolei dzień w roku ta data przed­stawia, należy w łańcuchu ją repre­zentującym znależć dwie pozycje separa­tora rozdzie­lającego poszcze­gólne elementy (dzień, miesiąc i rok), a potem te elementy wyłuskać.

W przypadku formatu DD.MM.RRRR separa­torem jest kropka. W zaprezen­towanej poniżej drugiej wersji pro­gramu wyszuki­wanie kropki w łań­cuchu daty reali­zują metody IndexOf (pierwsze wystą­pienie) i LastIndexOf (ostatnie wystą­pienie) klasy String. Przed pierw­szym wystą­pieniem kropki (pozy­cja i) znajduje się numer dnia, pomiędzy pierw­szym a drugim (pozy­cja j) numer miesiąca, a po drugim numer roku (rys.). Ele­menty daty są nastę­pnie wydzie­lane (metody Substring klasy String) i konwer­towane na wartości całko­wite (metoda ToInt32 klasy Convert).

Wprowadzanie daty z konsoli jest operacją podatną na błąd użytko­wnika, dlatego wpisany przezeń tekst wymaga spraw­dzenia. Do wychwy­cenia nienor­malnych sytuacji i reago­wania na nie program korzysta z mecha­nizmu obsługi wyjątków. Wychwy­tuje następu­jące sytuacje wyjątkowe:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kalendarz.Greg;

namespace Dzien2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Data (DD.MM.RRRR): ");
            try
            {
                string s = Console.ReadLine().Trim();
                int i = s.IndexOf('.');
                int j = s.LastIndexOf('.');
                if (i < 1 || i >= j - 1 || j == s.Length || s.IndexOf(' ') > 0)
                    throw new Exception("Nieprawidłowy zapis daty.");
                int r = Convert.ToInt32(s.Substring(j + 1));
                if (r < 1 || r > 9999)
                    throw new Exception("Nieprawidłowy numer roku.");
                int m = Convert.ToInt32(s.Substring(i + 1, j - i - 1));
                if (m < 1 || m > 12)
                    throw new Exception("Nieprawidłowy numer miesiąca.");
                int d = Convert.ToInt32(s.Substring(0, i));
                if (d < 1 || d > Kalend.Dmax(m, r))
                    throw new Exception("Nieprawidłowy numer dnia.");
                if (r < 1582 || (r == 1582 && (m < 10 || (m == 10 && d < 15))))
                    throw new Exception("Data < 15.10.1582 (kalendarz gregoriański).");
                Console.WriteLine("{0}, {1} dzień roku.",
                                  Nazwa[Kalend.Dtyg(d, m, r)], Kalend.Ndr(d, m, r));
                Console.WriteLine("Liczba dni do końca roku: {0}.", Kalend.Kdr(d, m, r));
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        static string[] Nazwa = {"Niedziela", "Poniedziałek", "Wtorek",
                                 "Środa", "Czwartek", "Piątek", "Sobota"};
    }
}

Program dodatkowo wypisuje liczbę dni, jaka pozostała od podanej daty do końca roku. Oto wynik jego wykonania dla przykła­dowej daty:

Warto odnotować, że w przestrzeni System dostępna jest struktura (upro­szczona klasa) DateTime reprezen­tująca datę i godzinę. Posiada ona szereg właści­wości i metod, m.in.:

Ponadto w przestrzeni System.Globalization zdefinio­wana jest klasa DateTimeFormatInfo, w której znajduje się właści­wość staty­czna CurrentInfo zawiera­jąca konwencje formato­wania liczb, daty i czasu, nazwy dni i miesięcy, kalen­darz i szereg innych infor­macji wynika­jących z usta­wień regio­nalnych i naro­dowych. Wymieńmy tylko niektóre z jej składowych:

A oto program analogiczny do poprzedniego, korzysta­jący ze stru­ktury DateTime i klasy DateTimeFormatInfo zamiast klasy Kalend:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;

namespace Dzien3
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Data {0}: ", DateTimeFormatInfo.CurrentInfo.ShortDatePattern);
            try
            {
                DateTime dt = DateTime.Parse(Console.ReadLine().Trim());
                int r = dt.Year;
                int m = dt.Month;
                if (r < 1582 || (r == 1582 && (m < 10 || (m == 10 && dt.Day < 15))))
                    throw new Exception("Data < 15.10.1582 (kalendarz gregoriański).");
                Console.WriteLine("{0}, {1} dzień roku.",
                        DateTimeFormatInfo.CurrentInfo.GetDayName(dt.DayOfWeek), dt.DayOfYear));
                Console.WriteLine("Liczba dni do końca roku: {0}.",
                        (new DateTime(r, 12, 31)).DayOfYear - dt.DayOfYear);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }
}

Gwoli wyjaśnienia, wartością właściwości DayOfWeek jest element listy: Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday (nazwa dnia tygo­dnia w języku angiel­skim). Domyślnie pierwszy element tego wyliczenia ma przypisaną wartość 0, drugi 1, ..., siódmy 6. Zatem gdyby zamiast takiej wartości wylicze­niowej trzeba było użyć odpowia­dającej jej liczby, nale­żałoby wykonać rzutowanie (int)dt.DayOfWeek. Zauważmy jeszcze, że w celu obli­czenia liczby dni, jaka pozostała od rozpatry­wanej daty do końca roku, tworzony jest obiekt DateTime dla osta­tniego dnia tego roku. Dla porównania poniższy rysunek przedsta­wia wynik wyko­nania programu.


Opracowanie przykładu: wrzesień 2018