Gdy skrypt ma zapisać log, utworzyć nazwę pliku albo sprawdzić termin wykonania zadania, potrzebuje wiarygodnej daty i godziny. W PowerShellu służy do tego przede wszystkim polecenie Get-Date, które zwraca bieżący czas oraz pozwala go formatować, porównywać i przeliczać. Pokażę praktyczne przykłady, różnicę między datą jako obiektem a tekstem, obsługę UTC oraz zastosowanie w aplikacjach desktopowych.
Najważniejsze reguły pracy z datą w PowerShellu
-
Get-Datebez parametrów zwraca lokalną datę i godzinę komputera. - Parametr
-Formattworzy tekst, więc nie należy używać go zbyt wcześnie w obliczeniach. - Do logów i nazw plików najlepiej sprawdza się format
yyyy-MM-dd HH:mm:ssalbo jego wariant bez znaków specjalnych. - Przy komunikacji między komputerami bezpieczniej przechowywać czas w UTC.
- W aplikacjach WPF warto przekazywać do widoku obiekt
DateTime, a formatowanie zostawić warstwie interfejsu.
Get-Date w PowerShellu od podstaw
Najprostsze użycie nie wymaga żadnych parametrów. Wpisuję polecenie i otrzymuję bieżącą datę oraz godzinę zgodną z ustawieniami systemu Windows.
Get-DateWynikiem jest obiekt typu System.DateTime, a nie zwykły tekst. To ważne, ponieważ mogę od razu korzystać z jego właściwości i metod.
$now = Get-Date
$now.Year
$now.Month
$now.Day
$now.Hour
$now.Minute
$now.DayOfWeekW praktyce często interesuje mnie tylko konkretna informacja. Właściwość .Date usuwa część godzinową, a .TimeOfDay zwraca samą porę dnia.
$today = (Get-Date).Date
$currentTime = (Get-Date).TimeOfDayJeżeli potrzebuję wartości zbudowanej na podstawie konkretnych składników, mogę przekazać parametry takie jak -Year, -Month, -Day czy -Hour.
Get-Date -Year 2026 -Month 10 -Day 15 -Hour 9 -Minute 30Do odczytywania podanej daty wygodniejszy jest parametr -Date. Przy datach wpisywanych jako tekst trzeba uważać na kulturę systemu. Zapis ISO 8601 jest zwykle bezpieczniejszy niż niejednoznaczne wartości w rodzaju 03/04/2026.
Get-Date -Date '2026-10-15T09:30:00'Formatowanie bez utraty kontroli nad typem danych
Formatowanie jest proste, ale właśnie tutaj pojawia się jeden z częstszych błędów. Polecenie Get-Date -Format zwraca łańcuch znaków, a nie obiekt DateTime. Taki wynik dobrze wygląda na ekranie, lecz nie nadaje się już bezpośrednio do dodawania dni ani porównywania dat.
Get-Date -Format 'dd.MM.yyyy HH:mm:ss'Gdy chcę zachować typ daty, pobieram obiekt do zmiennej, a formatuję dopiero podczas wyświetlania.
$date = Get-Date
$date.AddDays(7)
$date.ToString('dd.MM.yyyy')W skryptach działających na komputerach z różnymi ustawieniami regionalnymi preferuję format jednoznaczny. Dzięki temu logi i nazwy plików sortują się chronologicznie, a dzień i miesiąc nie zamieniają się miejscami.
| Zastosowanie | Przykład | Dlaczego warto |
|---|---|---|
| Log czytelny dla człowieka | dd.MM.yyyy HH:mm:ss |
Naturalny zapis używany w Polsce |
| Log techniczny | yyyy-MM-dd HH:mm:ss |
Jednoznaczny i łatwy do sortowania |
| Nazwa pliku | yyyyMMdd-HHmmss |
Brak znaków problematycznych w systemie plików |
| Wymiana danych | o |
Precyzyjny format round-trip dla .NET |
Do nazw plików używam na przykład takiego zapisu:
$fileName = "raport-$(Get-Date -Format 'yyyyMMdd-HHmmss').csv"Warto odróżnić -Format od -DisplayHint. Ten drugi wpływa głównie na sposób prezentacji wyniku w konsoli, natomiast nie jest zamiennikiem właściwego formatowania danych przekazywanych dalej.
Obliczenia, zakresy i porównywanie czasu
Obiekt zwracany przez Get-Date pozwala wykonywać obliczenia bez ręcznego przeliczania sekund czy dni. Najczęściej korzystam z metod AddDays, AddHours i AddMinutes.
$today = Get-Date
$tomorrow = $today.AddDays(1)
$inTwoHours = $today.AddHours(2)
$lastWeek = $today.AddDays(-7)Do obliczania różnicy między datami służy odejmowanie. Wynikiem jest obiekt TimeSpan, który udostępnia między innymi liczbę dni, godzin i minut.
$start = Get-Date '2026-09-01T08:00:00'
$end = Get-Date '2026-09-03T17:30:00'
$duration = $end - $start
$duration.Days
$duration.TotalHoursJeżeli sprawdzam termin wykonania zadania, nie formatuję daty przed porównaniem. Porównanie dwóch tekstów może dać wynik pozornie poprawny tylko wtedy, gdy oba teksty mają właściwy, sortowalny układ.
$deadline = Get-Date '2026-10-01T17:00:00'
$now = Get-Date
if ($now -lt $deadline) {
'Termin jeszcze nie minął'
}
else {
'Termin został przekroczony'
}Ten schemat dobrze sprawdza się przy wygaszaniu plików tymczasowych, kontroli certyfikatów i monitorowaniu zadań Windows. Z mojego doświadczenia wynika, że więcej problemów powoduje niejednoznaczne parsowanie daty niż samo porównanie.
Czas lokalny, UTC i strefy czasowe
Domyślnie Get-Date zwraca czas lokalny komputera. Na pojedynczym stanowisku pracy zwykle to wystarcza, ale przy logach z wielu urządzeń, usługach Azure albo wymianie danych między krajami szybko pojawia się problem różnych stref czasowych.
Do uzyskania czasu UTC można użyć konwersji obiektu:
$localTime = Get-Date
$utcTime = $localTime.ToUniversalTime()W nowszych wersjach PowerShellu dostępny jest również parametr -AsUTC.
Get-Date -AsUTCW starszym Windows PowerShellu bezpiecznym i czytelnym rozwiązaniem pozostaje ToUniversalTime(). Alternatywnie w kodzie .NET można użyć właściwości [datetime]::UtcNow.
[datetime]::Now
[datetime]::UtcNowSam zapis UTC nie rozwiązuje każdego problemu. Jeśli aplikacja musi pokazać użytkownikowi czas w konkretnej strefie, trzeba wykonać jawną konwersję i uwzględnić zmianę czasu letniego. Warto też rozważyć DateTimeOffset, gdy znaczenie ma zarówno data, jak i przesunięcie względem UTC.
$offsetNow = [datetimeoffset]::Now
$offsetNow.OffsetMoja praktyczna zasada jest prosta: lokalny czas służy do prezentacji, a UTC do zapisu, porównań i komunikacji między systemami. Dzięki temu aplikacja nie zaczyna zachowywać się inaczej po zmianie strefy albo po przejściu na czas zimowy.
Daty w aplikacjach desktopowych i WPF
Przekazywanie dat do tabeli
PowerShell często przygotowuje dane dla aplikacji desktopowej albo generuje plik, który później jest ładowany do interfejsu WPF. Jeżeli data ma trafić do tabeli, lepiej przekazać prawdziwy obiekt DateTime niż tekst utworzony przez -Format. Dzięki temu sortowanie odbędzie się chronologicznie, a nie alfabetycznie.
$items = @(
[pscustomobject]@{
Name = 'Raport A'
CreatedAt = Get-Date
},
[pscustomobject]@{
Name = 'Raport B'
CreatedAt = (Get-Date).AddHours(-3)
}
)W widoku WPF format można ustawić osobno, bez niszczenia typu danych w modelu. Przy pracy z tabelą przydatne będą również zasady opisane w materiale o tym, jak działa DataGrid w WPF, szczególnie gdy użytkownik ma sortować albo edytować wartości.
Przeczytaj również: VCRUNTIME140.dll i MSVCP140.dll - jak naprawić błąd?
Wprowadzanie daty przez użytkownika
Jeżeli data pochodzi z pola tekstowego, nie zakładam, że użytkownik zawsze wpisze poprawny format. W aplikacji warto rozdzielić trzy etapy: pobranie tekstu, jego walidację oraz konwersję do DateTime.
$text = '15.10.2026 09:30'
$format = 'dd.MM.yyyy HH:mm'
$date = [datetime]::ParseExact(
$text,
$format,
[Globalization.CultureInfo]::GetCultureInfo('pl-PL')
)ParseExact wymaga dokładnego wzorca i dobrze pasuje do formularzy, w których format jest z góry ustalony. Gdy dopuszczam kilka wariantów zapisu, używam ostrożnie TryParse albo TryParseExact, ponieważ błędny tekst nie powinien przerywać działania całej aplikacji.
W przypadku formularzy WPF szczególnie ważna jest walidacja w WPF. Powinna poinformować użytkownika o błędzie przy polu, a nie dopiero po kliknięciu przycisku zapisującego dane.
Małe decyzje, które chronią skrypt przed błędami
- Nie formatuj daty przed wykonaniem obliczeń. Najpierw pracuj na
DateTime, a tekst twórz na samym końcu. - Nie używaj niejednoznacznych zapisów typu
03/04/2026, jeśli skrypt może działać na komputerach z inną kulturą. - Do logów i komunikacji między systemami wybieraj UTC oraz format jednoznaczny dla programu.
- Przy nazwach plików pomijaj dwukropki, ukośniki i inne znaki niedozwolone w Windows.
- Jeśli czas pochodzi z wielu komputerów, sprawdź synchronizację zegarów systemowych. Samo
Get-Dateodczytuje to, co twierdzi lokalny zegar.
Najkrótsza recepta brzmi więc tak: Get-Date pobiera bieżący czas, obiekt DateTime służy do obliczeń, a -Format wykorzystuję dopiero wtedy, gdy potrzebuję gotowego tekstu. Taki podział jest prosty, dobrze skaluje się w skryptach PowerShell i ogranicza liczbę niespodzianek w aplikacjach desktopowych.
