Um momento
0x120Lesson 19 of 24

Dates, times and durations

Parse, format and calculate with dates and time spans without being tripped up by culture, time zones or month ends.

26 min 7-question quiz 2 code exercises
By the end of this lesson you can
  • 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-Date gives you now. Get-Date -Year 2026 -Month 3 -Day 14 builds 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') or Get-Date -Format 'yyyy-MM-dd'. Watch the case: MM is month, mm is minute; HH is the 24-hour clock, hh the 12-hour one.
dates.ps1
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')
Output
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, .Minutes are the parts: 8 hours 25 minutes has .Hours = 8 and .Minutes = 25.
  • .TotalHours, .TotalMinutes are 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.

timespans.ps1
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')
Output
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.

parsing.ps1
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}
Output
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?

0 of 8 sortedScore 0/0
  • “[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 (MM month, mm minute, HH 24-hour).

  • Add with .AddDays()/.AddMonths(); subtracting dates gives a [timespan].

  • .Hours is a part, .TotalHours is the whole span - choose deliberately.

  • Parse known formats with ParseExact (or TryParseExact) 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.

Exercise 1

The hatching schedule

+25 XP

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
script.ps1
Loading editor…

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.

Exercise 2

The nap tracker

+25 XP

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
script.ps1
Loading editor…

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…

Gostou da aula? 😆👍
Apoie nosso trabalho com uma doação: