🔥 Darmowa Roadmapa .NET — kompletny plan nauki do pierwszej pracy. Pobierz i dołącz do Listy VIP →

TimeSpan w C# — Hours vs TotalHours i pełne godziny

TimeSpan w C# — rok nauki po 20 minut dziennie, a Hours pokazuje tylko 1 godzinę

Uczysz się programowania 20 minut dziennie przez cały rok. Piszesz w C# kalkulator, który ma powiedzieć, ile to godzin, a on odpowiada: 1 godzina i 40 minut. Program się nie wywrócił, kompilator nic nie zgłosił, nie było nawet ostrzeżenia. A „oczywista” naprawa, która przychodzi do głowy jako pierwsza, też podaje zły wynik — tylko w inny sposób.

Ten wpis to wersja tekstowa odcinka Program .NET Developer #5 na YouTube. Kod jest ten sam co w filmie, a każdy wynik uruchomiłem na .NET 10. Jeśli twój program liczy czas — czas gry, długość filmu, godziny pracy, czas do końca promocji — to dotyczy także ciebie. Zakładam, że znasz zmienne i typy w C#; resztę wyjaśniam po drodze.

TimeSpan w C#: rok nauki = 1 godzina

Kalkulator ma dwie liczby: ile minut dziennie i przez ile dni. Zamieniamy je na odcinek czasu i wypisujemy godziny oraz minuty:

int minutyDziennie = 20;   // tyle uczysz się każdego dnia
int dni = 365;             // przez cały rok

TimeSpan nauka = TimeSpan.FromMinutes(minutyDziennie * dni);

Console.WriteLine($"Rok nauki: {nauka.Hours} h {nauka.Minutes} min");

TimeSpan to typ z biblioteki .NET — po polsku „odcinek czasu”. Trzyma długość czasu (godzinę, trzy dni, 7300 minut), a nie konkretny moment w kalendarzu; do momentów służy DateTime. Metoda TimeSpan.FromMinutes zamienia liczbę minut na taki odcinek. Znak $ przed cudzysłowem pozwala wstawić wartość w nawiasy klamrowe — więcej o tym we wpisie o interpolacji stringów. Wynik:

Rok nauki: 1 h 40 min

Policzmy sami: 20 × 365 = 7300 minut. To dużo więcej niż jedna godzina. Kod się skompilował, program się nie zatrzymał, a wynik jest zły. To najgorszy rodzaj błędu, bo nikt cię o nim nie ostrzeże — zauważysz go tylko wtedy, gdy sam przeliczysz wynik.

Zasada: to, że kod się kompiluje i działa, nie znaczy, że liczy dobrze. Wynik, który dotyczy czasu, przelicz choć raz ręcznie.

Co jest w środku TimeSpan: 5.01:40:00

Wypiszmy cały odcinek czasu naraz, a pod spodem trzy jego części:

TimeSpan nauka = TimeSpan.FromMinutes(20 * 365);

Console.WriteLine($"Całość: {nauka}");
Console.WriteLine($"Days: {nauka.Days}");
Console.WriteLine($"Hours: {nauka.Hours}");
Console.WriteLine($"Minutes: {nauka.Minutes}");
Całość: 5.01:40:00
Days: 5
Hours: 1
Minutes: 40

5.01:40:00 czytamy: 5 dni, 1 godzina, 40 minut i 0 sekund. Przed kropką są dni, po kropce godziny, minuty i sekundy, jak na zegarku. Reszta roku nie zginęła — jest w dniach. Pięć dni to 120 godzin, a TimeSpan trzyma je po prostu w innym miejscu.

Pomyśl o tym jak o zegarze z trzema tarczami:

TarczaWłaściwośćZakresTu pokazuje
dniDaysod 0 w górę5
godzinyHours0–231
minutyMinutes0–5940

Kiedy tarcza godzin dobije do 24, wraca na zero, a tarcza dni przeskakuje o jeden. Tak samo jak zegar na ścianie: o pierwszej w nocy pokazuje jedynkę, a nie liczbę godzin, które minęły od twoich urodzin. Hours nie znaczy „wszystkie godziny” — pokazuje tylko to, co jest na tarczy godzin.

Dlatego ten błąd jest podstępny. Gdybyś sprawdził kalkulator na jednym miesiącu (20 minut × 30 dni), dostałbyś Hours = 10 — i to jest prawda. Błąd wychodzi dopiero wtedy, gdy wynik przekroczy jedną dobę.

Zasada: Days, Hours i Minutes to pojedyncze tarcze, a nie cały czas. Hours jest zawsze w zakresie 0–23.

Minutes czy TotalMinutes?

Skoro Minutes to tylko tarcza minut, jak dostać cały czas? TimeSpan ma do tego drugi zestaw właściwości, zaczynających się od Total — „całkowity”:

TimeSpan nauka = TimeSpan.FromMinutes(20 * 365);

Console.WriteLine($"Minutes: {nauka.Minutes}");
Console.WriteLine($"TotalMinutes: {nauka.TotalMinutes}");

Zanim przewiniesz dalej, odpowiedz sam:

Zgadnij, zanim klikniesz

03-Total.cs — tarcza czy całość?

Zmienna nauka to 5.01:40:00 — 20 minut dziennie przez rok, czyli 7300 minut. Co wypisze każda linijka?

nauka.Minutes
nauka.TotalMinutes
Uruchomione na .NET 10: Minutes to 40 — tylko tarcza minut. TotalMinutes to 7300 — cały czas w minutach. Bez Total pytasz o jedną tarczę, z Total — o całość.
Minutes: 40
TotalMinutes: 7300

Minutes to 40, bo tyle jest na tarczy minut. TotalMinutes to 7300 — cały rok nauki zamieniony na minuty, dokładnie tyle, ile wyszło z mnożenia. Tak samo działają TotalHours i TotalDays: każda odpowiada na pytanie „ile to razem, w jednej jednostce”. Jest jedna różnica, którą łatwo przeoczyć: właściwości z Total są typu double, czyli mogą mieć część po przecinku. Tarcze (Days, Hours, Minutes) są typu int.

Zasada: bez Total — jedna tarcza zegara (int). Z Total — cały czas w jednej jednostce, razem z ułamkiem (double).

Pułapka: naprawa przez TotalHours liczy 40 minut dwa razy

Teraz „oczywista” naprawa. Skoro Total daje całość, zamiast Hours piszemy TotalHours, a minuty zostawiamy, jak były:

TimeSpan nauka = TimeSpan.FromMinutes(20 * 365);

Console.WriteLine($"Rok nauki: {nauka.TotalHours} h {nauka.Minutes} min");
Rok nauki: 121,66666666666667 h 40 min

TotalHours to cały czas w godzinach, razem z ułamkiem. A to 0,666… godziny na końcu to właśnie 40 minut — dwie trzecie godziny zapisane po przecinku. Do tego dokleiliśmy jeszcze 40 minut z tarczy minut. Te same 40 minut policzyliśmy dwa razy: raz w ułamku, raz z tarczy. (Przecinek zamiast kropki w 121,66… to polskie ustawienia regionalne komputera — o tym, skąd się bierze, piszę we wpisie o formatowaniu daty i CultureInfo.)

Ta pułapka jest groźniejsza od pierwszej. Wynik 1 h 40 min jest na tyle absurdalny, że łatwo go zauważyć. Wynik 121,67 h 40 min wygląda „prawie dobrze” — i właśnie taki łatwo przepuścić dalej.

Zasada: nie mieszaj dwóch rodzajów pytań w jednym zdaniu. Albo pytasz o tarcze (Days, Hours, Minutes), albo o całość w jednej jednostce (TotalHours, TotalMinutes). Pół na pół zawsze da bałagan.

Poprawka: pełne godziny z Days * 24 + Hours

Potrzebujemy pełnych godzin, bez ułamka. Tarcze już znamy, więc składamy pełne godziny z dwóch tarcz: każdy dzień to 24 godziny, do tego dokładamy to, co jest na tarczy godzin. Minuty bierzemy z tarczy minut:

int minutyDziennie = 20;   // tyle uczysz się każdego dnia
int dni = 365;             // przez cały rok

TimeSpan nauka = TimeSpan.FromMinutes(minutyDziennie * dni);

int godziny = nauka.Days * 24 + nauka.Hours;

Console.WriteLine($"Rok nauki: {godziny} h {nauka.Minutes} min");
Rok nauki: 121 h 40 min

Gwiazdka to mnożenie, a C# — jak matematyka — mnoży przed dodawaniem: 5 × 24 + 1 = 121. Wszystkie operatory i ich kolejność znajdziesz we wpisie o operatorach w C#.

Sprawdźmy drugą drogą: 121 × 60 + 40 = 7300 minut. Dokładnie tyle, ile pokazał TotalMinutes. Tym razem kalkulator mówi prawdę.

Trzy sposoby zapytania o godziny i kiedy który ma sens:

WyrażenieWynik dla 7300 minutKiedy używaćHaczyk
nauka.Hours1zegar w obrębie doby: „która godzina na tarczy”po przekroczeniu doby gubi dni — bez błędu
nauka.TotalHours121,66666666666667obliczenia: stawka za godzinę, średnia, porównaniedouble z ułamkiem; z Minutes daje 40 minut dwa razy
nauka.Days * 24 + nauka.Hours121wypisanie „X h Y min” dla człowiekatrzeba pamiętać o dniach; minuty bierzesz z Minutes

Zasada: wynik zawsze sprawdź drugą drogą — na przykład przez TotalMinutes. Jeśli obie drogi dają to samo, liczysz dobrze.

Sprawdź sam: tarcze zegara dla twoich minut

Wybierz, ile minut dziennie się uczysz. Wstawka pokazuje trzy tarcze i to, co dla tej liczby wypisze kalkulator z błędem (01-Rok.cs) i po poprawce (05-Final.cs). Wszystkie siedem wariantów uruchomiłem na .NET 10.

Sprawdź sam

Tarcze zegara — rok nauki

Ile minut dziennie? (przez 365 dni)

Daystarcza dni
Hourstarcza godzin, 0–23
Minutestarcza minut, 0–59

Całość: · TotalMinutes: · TotalHours:

TimeSpan nauka = TimeSpan.FromMinutes(minutyDziennie * dni); int godziny = nauka.Days * 24 + nauka.Hours; Console.WriteLine($"Rok nauki: {godziny} h {nauka.Minutes} min");

Ściągawka na code review

WłaściwośćTypCo zwracaDla 5.01:40:00
Daysinttarcza dni5
Hoursinttarcza godzin, 0–231
Minutesinttarcza minut, 0–5940
TotalHoursdoublecały czas w godzinach, z ułamkiem121,66666666666667
TotalMinutesdoublecały czas w minutach7300

Przeglądając kod, szukaj .Hours i .Minutes w miejscach, gdzie odcinek czasu może być dłuższy niż doba (sumy, czas „od początku”, „od rejestracji”, „w tym roku”), i zdań, które łączą Total… z tarczą w jednym napisie. Gdzie to spotkasz? Wszędzie tam, gdzie program liczy czas: czas gry, długość filmu, godziny pracy nad projektem, czas do końca promocji. Dopóki wynik jest krótszy niż doba, Hours działa. Kiedy przekroczy dobę, zaczyna kłamać. Gdy wynik wyjdzie dziwny, przejdź program krok po kroku debugerem — w podglądzie zmiennych widać wszystkie tarcze naraz.

Zadanie: 25 minut dziennie

Tym razem 25 minut dziennie przez rok. Program wypisuje dni, godziny i TotalHours:

TimeSpan nauka = TimeSpan.FromMinutes(25 * 365);

Console.WriteLine($"Days: {nauka.Days}");
Console.WriteLine($"Hours: {nauka.Hours}");
Console.WriteLine($"TotalHours: {nauka.TotalHours}");
  1. Zanim uruchomisz program, zapisz trzy liczby, które wypisze.
  2. Dopisz linijkę, która pokaże pełne godziny i minuty.
  3. Celowo zepsuj: spróbuj wpisać do nauka.Hours własną liczbę i przeczytaj komunikat kompilatora.

Pytanie bonusowe do komentarza pod filmem: co wypisze {nauka} — cały odcinek czasu w nawiasach klamrowych? Odpowiedzi są w przypiętym komentarzu pod filmem.

Podsumowanie

  • TimeSpan trzyma czas jak zegar z trzema tarczami: Days, Hours (0–23) i Minutes (0–59) — każda osobno.
  • Hours to nie wszystkie godziny. Po przekroczeniu doby reszta przeskakuje na tarczę dni, bez błędu i bez ostrzeżenia.
  • Właściwości z Total dają cały czas w jednej jednostce, jako double z ułamkiem. TotalHours razem z Minutes liczy te same minuty dwa razy.
  • Pełne godziny: nauka.Days * 24 + nauka.Hours, minuty z nauka.Minutes — i sprawdzenie drugą drogą przez TotalMinutes.

🎥 Wersja wideo: ten sam przykład krok po kroku — Program .NET Developer #5 — Rok nauki: 1 godzina
🔴 Napisz taki kalkulator sam — na żywo: „Pierwszy program w C# — zrób to ze mną”: instalujemy Visual Studio i piszesz razem ze mną kalkulator nauki, od zera — transmisja 9.11.2026 o 19:00, potem nagranie pod tym samym linkiem
🎓 Skąd ten temat: kurs C# Podstawy Programowania — lekcje o obsłudze daty i czasu. Kurs to poziom 1 Programu .NET Developer.
📘 Darmowa roadmapa .NET Developera: dev-hobby.pl/lista-vip

Zobacz

Mariusz Jurczenko
Mariusz Jurczenko
Senior .NET Developer · 10+ lat doświadczenia komercyjnego

Programista .NET z doświadczeniem komercyjnym w firmach takich jak NFZ, Kamsoft, Diagnostyka, Hermes Reply Polska czy Etisoft Smart Solutions. Twórca kursów, z których skorzystało już ponad 11 000 osób w Strefie Kursów i ponad 1 000 kursantów na dev-hobby.pl.

Specjalizacja: Clean Code, Clean Architecture i uczenie programowania tak, żeby dało się je naprawdę zrozumieć — nie wykuć.

🚀 Co dalej?

Zobacz to w praktyce na wideo i pobierz darmową roadmapę, żeby ułożyć naukę w spójną ścieżkę do pierwszej pracy.

Dodaj komentarz

czytanie to początek

Zamień wiedzę w umiejętności

Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.

Pobieram roadmapę →