CodeGym /Kursy /C# SELF /Obliczenia i pomocnicze klasy do dat i czasu

Obliczenia i pomocnicze klasy do dat i czasu

C# SELF
Poziom 15 , Lekcja 4
Dostępny

1. Podstawowe zadania przy pracy z datą i czasem

Praca z datami i czasem często wywołuje lekką (a czasem wcale nielekką) panikę nawet u doświadczonych devów. Trzeba porównywać daty, liczyć interwały, dodawać lub odejmować dni/miesiące/lata, liczyć wiek, określać dzień tygodnia i dużo więcej.

To wszystko — typowe zadania dla trackerów zadań i kalendarzy, obsługi abonamentów czy subskrypcji, rozliczeń finansowych, raportów statystycznych i oczywiście na rozmowach rekrutacyjnych (np. "policz liczbę dni roboczych między dwiema datami").

W C# i .NET do tych zadań są wbudowane klasy i metody. Najważniejsze — większość obliczeń robi się przez obiektowy, maksymalnie bezpieczny i czytelny API.

2. Struktura TimeSpan — mierzymy interwały czasu

Wszystko zaczyna się od struktury TimeSpan. To taki "kawałek" czasu: np. 5 dni, 3 godziny, 7 minut i 21 sekund.

Jak stworzyć TimeSpan?

Możesz "odjąć" dwie daty, możesz stworzyć jawnie:

// Różnica między dwiema datami to zawsze TimeSpan!
DateTime start = new DateTime(2025, 5, 1, 7, 0, 0);
DateTime end = new DateTime(2025, 5, 2, 11, 30, 0);

TimeSpan duration = end - start; // Pełna magia!
Console.WriteLine(duration); // 1.04:30:00 (1 dzień, 4 godziny, 30 minut)

Możesz jawnie stworzyć TimeSpan przez parametry konstruktora:

TimeSpan span = new TimeSpan(2, 14, 18, 0); // 2 dni, 14 godzin, 18 minut, 0 sekund
Console.WriteLine(span); // 2.14:18:00

Alternatywny sposób tworzenia — przez statyczne metody, które często są czytelniejsze:

TimeSpan fiveMinutes = TimeSpan.FromMinutes(5);
TimeSpan twoHours = TimeSpan.FromHours(2);
TimeSpan oneWeek = TimeSpan.FromDays(7);

Jakie właściwości ma TimeSpan?

Właściwość Opis
Days
Całkowita liczba dni
Hours
Część godzinowa
Minutes
Część minutowa
Seconds
Część sekundowa
TotalDays
Czas w dniach (z ułamkiem)
TotalHours
Czas w godzinach (z ułamkiem)
TotalMinutes
Czas w minutach (z ułamkiem)
TotalSeconds
Czas w sekundach (z ułamkiem)
Console.WriteLine($"Dni: {duration.Days}, Wszystkich godzin: {duration.TotalHours}");

Jak dodać/odjąć TimeSpan od daty?

DateTime now = DateTime.Now;
DateTime future = now.Add(duration); // Dodaliśmy duration do now
DateTime past = now.Subtract(TimeSpan.FromDays(10)); // Minus 10 dni

Console.WriteLine(future);
Console.WriteLine(past);

3. Kalkulator dat: liczymy różnicę między datami

Skill, który przyda się praktycznie zawsze. Na przykład ktoś chce wiedzieć, ile zostało do urlopu, a ktoś inny — kiedy kończy się darmowy okres.

DateTime today = DateTime.Today;
DateTime vacation = new DateTime(2025, 8, 1);
TimeSpan untilVacation = vacation - today;

Console.WriteLine($"Do urlopu zostało {untilVacation.Days} dni!");

Zwróć uwagę: jeśli w odejmowaniu biorą udział tylko "daty" bez czasu (przez DateTime.Date albo DateTime.Today), wynik to zawsze całkowita liczba dni. A jeśli choć jedna data ma czas, różnica — z ułamkiem.


int days = (vacation - today).TotalDays; // Błąd kompilacji! TotalDays — double

Jeśli potrzebujesz liczby całkowitej — użyj .Days albo rzutuj na int przez (int)TotalDays.

4. Dodawanie i odejmowanie czasu: metody AddDays, AddMonths, AddHours, ...

C# nie wymaga ręcznego liczenia dni w każdym miesiącu, lat przestępnych i innych bóli. Po prostu używasz:

DateTime orderDate = new DateTime(2024, 4, 20);
DateTime deliveryDate = orderDate.AddDays(14); // Za 2 tygodnie

Console.WriteLine($"Towar będzie dostarczony {deliveryDate.ToShortDateString()}");
Metoda Co dodaje (albo odejmuje przy liczbie ujemnej)
AddDays(double)
Dni (obsługuje ułamki, np. 1,5 dnia)
AddMonths(int)
Miesiące (automatycznie uwzględnia długość miesiąca)
AddYears(int)
Lata (nawet z uwzględnieniem przestępnych)
AddHours(double)
Godziny
AddMinutes(double)
Minuty
AddSeconds(double)
Sekundy
DateTime birthday = new DateTime(2000, 2, 29);
DateTime nextYear = birthday.AddYears(1); // 2001-02-28 (nie 29, bo 2001 nie jest przestępny)
Console.WriteLine(nextYear.ToShortDateString()); // 28.02.2001

Pamiętaj: wszystkie metody zwracają nową instancję daty, oryginalna data się nie zmienia!

var dt = DateTime.Now;
dt.AddDays(5); // To NIE zmieni dt!
dt = dt.AddDays(5); // Teraz się zmieni

5. Pomocnicze metody do obliczeń

Obliczanie dnia tygodnia

W większości przypadków możesz użyć właściwości .DayOfWeek:

DateTime examDate = new DateTime(2025, 6, 19);
DayOfWeek day = examDate.DayOfWeek;
Console.WriteLine(day); // Wednesday

Możesz rzutować na liczbę całkowitą:

int number = (int)day; // Sunday == 0, Monday == 1, itd.

Sprawdzanie "dzisiaj", "wczoraj", "jutro"

Najprostsze porównania:

DateTime date = new DateTime(2025, 6, 18);

if (date.Date == DateTime.Today)
    Console.WriteLine("Dzisiaj!");
else if (date.Date == DateTime.Today.AddDays(-1))
    Console.WriteLine("Wczoraj!");
else if (date.Date == DateTime.Today.AddDays(1))
    Console.WriteLine("Jutro!");

Obliczanie wieku

Jedno z najczęstszych zadań — poprawne liczenie wieku człowieka. Proste odejmowanie lat nie zawsze działa dobrze:

public static int CalculateAge(DateTime birthDate, DateTime currentDate)
{
    int age = currentDate.Year - birthDate.Year;
    
    // Jeśli urodziny jeszcze nie były w tym roku
    if (currentDate.Month < birthDate.Month || 
        (currentDate.Month == birthDate.Month && currentDate.Day < birthDate.Day))
    {
        age--;
    }
    
    return age;
}

// Użycie
DateTime birth = new DateTime(1990, 8, 15);
DateTime today = DateTime.Today;
int age = CalculateAge(birth, today);
Console.WriteLine($"Wiek: {age} lat");

Praca z dniami roboczymi

Często trzeba policzyć liczbę dni roboczych między datami, pomijając weekendy:

public static int CountWorkingDays(DateTime startDate, DateTime endDate)
{
    int workingDays = 0;
    DateTime current = startDate;
    
    while (current <= endDate)
    {
        if (current.DayOfWeek != DayOfWeek.Saturday && 
            current.DayOfWeek != DayOfWeek.Sunday)
        {
            workingDays++;
        }
        current = current.AddDays(1);
    }
    
    return workingDays;
}

6. Jak powiązane są główne klasy

graph TD
    A(DateTime) --odejmowanie--> B(TimeSpan)
    A2(DateTime) --AddDays, AddMonths--> A
    A --ToLocalTime/ToUniversalTime--> C(DateTimeOffset)
    D(DateOnly) --ToDateTime--> A
    E(TimeOnly) --ToTimeSpan--> B
    A --DayOfWeek, Day, Month, Year--> F(Właściwości liczbowe)
    B(TimeSpan) --TotalDays, TotalHours, ...--> G(Właściwości długości)

7. Szybki "ściągacz": co zrobić jeśli...

Zadanie Czego użyć Przykład
Poznać różnicę między datami
TimeSpan duration = d2 - d1
(d2 - d1).Days
Dodać 2 tygodnie do daty
date.AddDays(14)
date.AddDays(14)
Obliczyć wiek Formuła z
.Year
i sprawdzeniem miesiąca/dnia
Patrz sekcja wyżej
Pobrać/ustawić tylko datę
DateOnly
DateOnly.FromDateTime(DateTime.Now)
Pobrać/ustawić tylko czas
TimeOnly
TimeOnly.FromDateTime(DateTime.Now)
Porównać daty Operatory
<
,
>
,
==
,
.CompareTo()
if (d1 < d2) ...
Przenieść do innej strefy czasowej
DateTimeOffset + ToOffset
dto.ToOffset(TimeSpan.FromHours(3))
Poznać numer tygodnia w roku
Calendar.GetWeekOfYear()
patrz dokumentacja
Poznać dzień tygodnia
date.DayOfWeek
Policzyć dni robocze Pętla ze sprawdzeniem
DayOfWeek
Patrz sekcja wyżej
1
Ankieta/quiz
Praca z datami, poziom 15, lekcja 4
Niedostępny
Praca z datami
Praca z datami, czasem i strefami czasowymi
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION