CodeGym /Kursy /C# SELF /Podstawowe typy pracy z czasem

Podstawowe typy pracy z czasem

C# SELF
Poziom 15 , Lekcja 0
Dostępny

1. Poznajemy typ DateTime

Data i czas — to taki podstawowy klocek każdej logiki biznesowej, że nie da się go olać nawet w najprostszych projektach. Często trzeba wiedzieć, kiedy użytkownik się zarejestrował, kiedy wysłać maila, dobrze obsłużyć rozkład lotów, strefy czasowe — wszędzie daty! Ale, jak pokazuje praktyka, praca z datą i czasem to jeden z najbardziej podstępnych tematów w programowaniu. 😅

C# daje dwa szczególnie ważne typy do pracy z czasem: DateTime i DateTimeOffset. W skrócie — jeden do prostych scenariuszy, drugi do zadań związanych ze strefami czasowymi i dokładnym przechowywaniem czasu.

Co to jest DateTime?

Typ DateTime — to struktura zdefiniowana w przestrzeni nazw System. Służy do przechowywania daty i czasu z dokładnością do 100 nanosekund (1/10 miliardowej sekundy).

  • Typ wartości (struct), czyli kopiowany przez wartość.
  • Zawiera zarówno datę, jak i czas.
  • Pozwala przechowywać tylko datę (2025-05-24), jak i datę z czasem (2025-05-24 15:17:42).
  • „Nie wie” o strefach czasowych, jeśli nie powiesz mu wprost.

2. Tworzymy DateTime

Opcji jest kilka, zobaczmy najważniejsze.

1. Aktualna data i czas

DateTime now = DateTime.Now;           // Lokalny czas komputera
DateTime utcNow = DateTime.UtcNow;     // Czas UTC (Greenwich)
  • Now — to "jak na twoim kompie", z uwzględnieniem lokalnej strefy Windows.
  • UtcNow — "uniwersalny", czyli światowy czas koordynowany. Mega wygodne do trzymania czasu np. w bazach danych albo systemach działających globalnie.

2. Konstruktory

// Rok, miesiąc, dzień
var date1 = new DateTime(2025, 5, 24);

// Rok, miesiąc, dzień, godziny, minuty, sekundy
var date2 = new DateTime(2025, 5, 24, 12, 0, 0);

// Rok, miesiąc, dzień, godziny, minuty, sekundy, milisekundy
var date3 = new DateTime(2025, 5, 24, 12, 0, 0, 500);

Miesiące nie są numerowane od zera! Czyli styczeń — to 1, grudzień — 12.

3. Parsowanie ze stringa

Bardzo często data przychodzi jako string! Na przykład, użytkownik wpisuje datę ręcznie.

string userInput = "2025-05-24 18:30";
DateTime parsed = DateTime.Parse(userInput); // Może rzucić wyjątek!

Dla bezpiecznego parsowania — używamy TryParse:

string input = "2025-05-24 18:30";
if (DateTime.TryParse(input, out DateTime result))
{
    Console.WriteLine($"Przekształcono pomyślnie: {result}");
}
else
{
    Console.WriteLine("Nie udało się przekształcić stringa na datę.");
}

4. Pobieranie daty "bez czasu"

DateTime today = DateTime.Today; // Bieżący dzień, ale czas = 00:00:00

Wyciąganie komponentów daty i czasu

Wszystkie właściwości można pobrać szybko:

var dt = new DateTime(2025, 5, 24, 15, 17, 42);

int year = dt.Year;         // 2025
int month = dt.Month;       // 5 (maj)
int day = dt.Day;           // 24
int hour = dt.Hour;         // 15
int minute = dt.Minute;     // 17
int second = dt.Second;     // 42
DayOfWeek dow = dt.DayOfWeek; // Piątek

3. Praca z typem DateTime

Dodawanie i odejmowanie dat

Czas w programowaniu leci szybko, więc żeby nie liczyć "ile godzin do deadline'u", używamy metod klasy:

DateTime now = DateTime.Now;
DateTime tomorrow = now.AddDays(1); // Jutro
DateTime afterFiveHours = now.AddHours(5); // Za 5 godzin
DateTime inTenMinutes = now.AddMinutes(10); // Za 10 minut

Różnica dwóch dat: TimeSpan

Różnica między dwiema datami — to osobna wartość, typ TimeSpan:

DateTime deadline = new DateTime(2026, 6, 1);
DateTime now = DateTime.Now;

TimeSpan untilDeadline = deadline - now;

Console.WriteLine($"Do deadline'u zostało dni: {untilDeadline.Days}");
Console.WriteLine($"Do deadline'u zostało godzin: {untilDeadline.TotalHours:N2}");

TimeSpan — to "różnica", a nie "konkretna data/czas"!

Sprawdzanie daty w przyszłości/przeszłości

if (deadline > now)
    Console.WriteLine("Deadline jeszcze przed nami!");
else
    Console.WriteLine("Deadline już minął! Szybko oddaj pracę!");

4. Jak daty są przechowywane pod maską

Dla wygody dodawania i odejmowania dat, programiści postanowili trzymać wszystkie daty jako liczbę sekund od początku naszej ery. Zakres wartości:

Właściwość Wartość
Minimalna data
DateTime.MinValue
= 0001-01-01 00:00:00
Maksymalna data
DateTime.MaxValue
= 9999-12-31 23:59:59.9999999
Jednostka miary 1 tick = 100 nanosekund

DateTime przechowuje nie tylko liczbę sekund, ale liczbę "ticków" (ticks) od specjalnej daty — 1 stycznia 0001 roku (tak, programiści nie znają dinozaurów, ich kalendarz jest bardziej surowy). Jeden tick = 100 nanosekund.

5. Typ DateTimeOffset

Czasem typ DateTime to za mało. Klasyczny przypadek: firma działa w dwóch krajach, mają różne strefy czasowe, a wszystkie spotkania zaplanowane są "wg mojego czasu". Co robić?

Czas zapisany jako DateTime jest często "abstrakcyjny": to po prostu zestaw cyferek i tick, dopóki nie powiesz wprost, w jakiej strefie to było. Na przykład, jeśli dostaniesz "2025-05-24 15:00", nie możesz być pewien — to czas Nairobi? Bagdadu? Berlina? (a jak jeszcze jest czas letni — trzymaj się mocno!).

Dlatego do zadań związanych z dokładnym momentem w czasie, a nie tylko "datą w kalendarzu", pojawił się drugi typ — DateTimeOffset. Tworzenie DateTimeOffset z podaniem przesunięcia (np. Nairobi +3 do UTC):


var localTime = new DateTimeOffset(2025, 5, 24, 15, 0, 0, TimeSpan.FromHours(3));

Używaj DateTimeOffset, jeśli:

  • Musisz znać dokładny moment w czasie (np. dla zdarzeń w logu powiązanych z czasem serwera).
  • Program działa z użytkownikami w różnych strefach czasowych.
  • Trzeba przechowywać/przekazywać czas z podaniem strefy (np. dla transakcji, zdarzeń, rozkładów).

6. Jak stworzyć DateTimeOffset?

  1. Aktualny moment czasu
    DateTimeOffset now = DateTimeOffset.Now; // Lokalny czas + przesunięcie
    DateTimeOffset utc = DateTimeOffset.UtcNow; // UTC (przesunięcie 0)
    
  2. Jawne tworzenie
    // Rok, miesiąc, dzień, godzina, minuta, sekunda, przesunięcie (np. +2 godziny)
    DateTimeOffset custom = new DateTimeOffset(2025, 5, 24, 20, 0, 0, TimeSpan.FromHours(2));
    
  3. Konwersja z DateTime
    DateTime dt = DateTime.Now;
    DateTimeOffset dto = new DateTimeOffset(dt); // Lokalna strefa zostanie pobrana automatycznie
    

Wyciąganie komponentów

DateTimeOffset dto = DateTimeOffset.Now;
var datePart = dto.Date;      // Tylko data
var timePart = dto.TimeOfDay; // Tylko czas
var offset = dto.Offset;      // Przesunięcie względem UTC, np. 03:00:00

Konwersja między strefami czasowymi

Magia przesunięć:

// Pobieramy datę w UTC
var now = DateTimeOffset.Now;
var utc = now.ToUniversalTime();
Console.WriteLine(utc); // Czas Greenwich

// Przekładamy na inną strefę
var berlinTime = utc.ToOffset(TimeSpan.FromHours(2));
Console.WriteLine(berlinTime); // Dla Berlina (CET +2)

7. Kiedy używać DateTime, a kiedy — DateTimeOffset?

Filozofia wyboru

Gdy chodzi o coś prostego i lokalnego — np. urodziny, datę publikacji artykułu czy deadline na ankietę do 15:00, najczęściej wystarczy DateTime. W takich przypadkach absolutny czas nie jest krytyczny, ważne tylko, że zdarzenie miało miejsce w określony dzień i godzinę, bez powiązania ze strefą czasową.

Ale jeśli trzeba zapisać konkretny moment z uwzględnieniem strefy czasowej, np. w logach, transakcjach czy systemach rozproszonych — lepiej użyć DateTimeOffset. Dzięki temu nie pogubisz się przy przekazywaniu czasu między systemami, szczególnie jeśli są w różnych strefach.

Scenariusz Typ Dlaczego
Urodziny
DateTime
Liczy się tylko data, strefa nieistotna (zwykle)
Czas logowania
DateTimeOffset
Ważny dokładny moment i przesunięcie
Termin ważności produktu
DateTime
Data końca, strefa nieistotna
Czas zdarzenia w logu
DateTimeOffset
Warto zawsze przechowywać z przesunięciem
2
Zadanie
C# SELF, poziom 15, lekcja 0
Niedostępne
Wyświetlanie bieżącej daty i godziny w różnych formatach
Wyświetlanie bieżącej daty i godziny w różnych formatach
2
Zadanie
C# SELF, poziom 15, lekcja 0
Niedostępne
Dodawanie i odejmowanie czasu
Dodawanie i odejmowanie czasu
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION