Dates, times and durations
Parse, format and calculate with dates and time spans without being tripped up by culture, time zones or month ends.
- Create dates with [datetime] casts and Get-Date, and format them with format strings
- Do date arithmetic with Add* methods, subtraction and TimeSpan properties
- Parse and exchange dates safely with ParseExact, ISO 8601 and UTC
The hatchery runs on dates: eggs incubate for weeks, dragons nap through midnight, and the vet visits every second Tuesday. A date in PowerShell is a .NET [datetime] object, so it carries handy properties (.Year, .DayOfWeek, .DayOfYear) and methods (.AddDays(), .AddMonths()).
Get-Dategives you now.Get-Date -Year 2026 -Month 3 -Day 14builds a specific date.- Casting a string with
[datetime]'2026-03-14 21:40'always uses the invariant culture - it reads the same on every computer. Stick to year-month-day order and it’s unambiguous. - Format with
.ToString('yyyy-MM-dd')orGet-Date -Format 'yyyy-MM-dd'. Watch the case:MMis month,mmis minute;HHis the 24-hour clock,hhthe 12-hour one.
1$laid = [datetime]'2026-03-14 21:40'
2$laid.DayOfWeek
3$laid.DayOfYear
4$laid.ToString('yyyy-MM-dd HH:mm')
5$laid.ToString('dd/MM/yy hh:mm tt', [cultureinfo]::InvariantCulture)
6$hatch = $laid.AddDays(45)
7"hatches $($hatch.ToString('yyyy-MM-dd')), a $($hatch.DayOfWeek)"
8[datetime]'2026-01-30' | ForEach-Object { $_.AddMonths(1).ToString('yyyy-MM-dd') }
9$laid.Date.ToString('yyyy-MM-dd HH:mm')Saturday 73 2026-03-14 21:40 14/03/26 09:40 PM hatches 2026-04-28, a Tuesday 2026-02-28 2026-03-14 00:00
Durations: TimeSpan
Subtract one date from another (or use New-TimeSpan -Start ... -End ...) and you get a [timespan] - a length of time. It has two families of properties that are easy to mix up:
.Days,.Hours,.Minutesare the parts: 8 hours 25 minutes has.Hours= 8 and.Minutes= 25..TotalHours,.TotalMinutesare the whole span in one unit: 8.4166… hours, or 505 minutes.
A 30-hour nap has .Hours = 6 (and .Days = 1), but .TotalHours = 30. Pick the one you mean.
1$nap = New-TimeSpan -Start '2026-03-14 21:40' -End '2026-03-15 06:05'
2"$($nap.Hours)h $($nap.Minutes)m"
3$nap.TotalMinutes
4[math]::Round($nap.TotalHours, 2)
5$nap.ToString()
6$untilFestival = [datetime]'2026-12-25' - [datetime]'2026-03-14'
7"$($untilFestival.Days) sleeps until the Winter Fire Festival"
8$long = [timespan]::FromHours(30)
9"Hours: $($long.Hours) Days: $($long.Days) TotalHours: $($long.TotalHours)"
10([datetime]'2026-03-14 21:40').Add($nap).ToString('HH:mm')8h 25m 505 8.42 08:25:00 286 sleeps until the Winter Fire Festival Hours: 6 Days: 1 TotalHours: 30 06:05
Parsing dates you didn’t write
Log files and CSVs arrive in every format imaginable. Is 03/04/2026 March 4th or April 3rd? It depends on who wrote it - and Get-Date '03/04/2026' answers using your computer’s culture, so the same script gives different answers in London and Seattle.
When you know the format, say so with [datetime]::ParseExact(text, format, [cultureinfo]::InvariantCulture). When the input might be junk, [datetime]::TryParseExact(...) returns $true or $false instead of throwing, and puts the result in a [ref] variable.
1$inv = [cultureinfo]::InvariantCulture
2$visit = [datetime]::ParseExact('14.03.2026 09:30', 'dd.MM.yyyy HH:mm', $inv)
3$visit.ToString('yyyy-MM-dd HH:mm')
4$parsed = [datetime]::MinValue
5foreach ($text in '2026-03-14', 'next Tuesday', '2026-02-30') {
6 if ([datetime]::TryParseExact($text, 'yyyy-MM-dd', $inv, 'None', [ref]$parsed)) {
7 "$text -> $($parsed.DayOfWeek)"
8 } else {
9 "$text -> not a date"
10 }
11}2026-03-14 09:30 2026-03-14 -> Saturday next Tuesday -> not a date 2026-02-30 -> not a date
Exchanging dates between systems? Use ISO 8601: Get-Date -Format o gives 2026-03-14T21:40:00.0000000+00:00 - sortable as plain text, unambiguous, and understood by every API. For log filenames, Get-Date -Format 'yyyy-MM-dd_HHmmss' sorts nicely in a folder.
Time zones: a [datetime] has a .Kind - Local, Utc or Unspecified. .ToUniversalTime() converts local time to UTC; store and compare in UTC when servers live in different zones, and convert to local time only for display. ([datetimeoffset] keeps the offset with the value, which is even safer.)
Try it
Safe everywhere, or culture roulette?
A script runs on keepers’ laptops in London, Tokyo and Seattle. Does each line give the same result on all of them?
“[datetime]'2026-03-14'”
“Get-Date '03/04/2026'”
“$d.ToString('yyyy-MM-dd')”
“$d.ToString('dddd d MMMM')”
“Get-Date -Format o”
“[datetime]::ParseExact($t, 'dd.MM.yyyy', [cultureinfo]::InvariantCulture)”
“'{0:d}' -f $d”
“$d.DayOfWeek”
Key takeaways
[datetime]'yyyy-MM-dd'casts are culture-proof; format with.ToString()or-Format(MMmonth,mmminute,HH24-hour).Add with
.AddDays()/.AddMonths(); subtracting dates gives a[timespan]..Hoursis a part,.TotalHoursis the whole span - choose deliberately.Parse known formats with
ParseExact(orTryParseExact) and the invariant culture; exchange dates as ISO 8601, ideally in UTC.
Lesson quiz
7 questions · pass with 5 correct · up to 50 XP
Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.
Practice: write PowerShell scripts
Write a script in the editor and run it for real against sample input, which is piped into your script as $input. Scripts run on PowerShell 6.2 through Try It Online (tio.run), a free public service, so these exercises avoid PowerShell 7-only syntax; your script and test input are sent there.
The hatching schedule
Each input line is a species and the date its egg was laid, like Firedrake 2026-03-14. Incubation takes Firedrake 45, Wyrm 60, Wisp 12 and Stormwing 30 days.
Print Firedrake egg laid 2026-03-14 hatches 2026-04-28 (Tuesday) for every egg, then first to hatch: <species> on <date>.
- Spring clutch
- Leap year
Lessons teach PowerShell 7; your script runs on PowerShell 6.2 via Try It Online (tio.run), a free public service, so stick to syntax that works there. Test input is piped into your script as $input. Your script and test input are sent to that service.
The nap tracker
Each input line is Dragon start end with 24-hour times, like Ember 21:40 06:05. If the end time is not after the start, the nap crossed midnight.
Print Ember slept 8h 25m for each nap, then longest: <dragon> and total: 31h 55m. Careful: a nap can last more than 24 hours in total, so the total needs whole hours.
- Overnight and afternoon
- Just after midnight
Lessons teach PowerShell 7; your script runs on PowerShell 6.2 via Try It Online (tio.run), a free public service, so stick to syntax that works there. Test input is piped into your script as $input. Your script and test input are sent to that service.
Questions about this lesson
Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.
Loading posts…