In PowerShell, dates, calendar timestamps, and time intervals are managed as strongly typed .NET objects rather than raw strings. Point-in-time values are represented by System.DateTime, while time intervals and durations are represented by System.TimeSpan. This object-oriented approach enables accurate date arithmetic, locale-aware formatting, and reliable timestamp comparisons without manual string parsing.
The Get-Date Cmdlet
The Get-Date cmdlet retrieves an object representing the current system date and time according to the local machine's clock and time zone settings.
Get-DateThursday, October 24, 2026 4:45:12 PMTo inspect the underlying structure and available members of the object returned by Get-Date:
(Get-Date).GetType().FullNameSystem.DateTimeConstructing Specific Dates
You can construct explicit DateTime instances by passing string literals or named parameters into Get-Date:
Get-Date -Date "2026-12-31 23:59:59"
Get-Date -Year 2026 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0Tuesday, December 31, 2026 11:59:59 PM
Wednesday, January 1, 2026 12:00:00 AMwhere:
-Dateaccepts a string that PowerShell parses into aDateTimeobject.- Without
-Date,Get-Datedefaults to the current system date and time.
DateTime Formatting Strings
While Get-Date outputs a DateTime object, automation tasks often require dates formatted as specific strings for log file names, REST API payloads, or database queries. The -Format parameter (or the .ToString() method) formats dates using standard .NET format specifiers.
Get-Date -Format "yyyy-MM-dd HH:mm:ss"2026-09-27 21:46:38where:
yyyy= 4-digit year,MM= 2-digit month,dd= 2-digit day.HH= 24-hour format hour,mm= minutes,ss= seconds.
Common Custom Format Specifiers
| Specifier | Description | Example Output |
|---|---|---|
yyyy |
4-digit calendar year | 2026 |
MM |
2-digit month (01-12) |
10 |
MMM / MMMM |
Abbreviated / Full month name | Oct / October |
dd |
2-digit day of the month (01-31) |
24 |
dddd |
Full day name | Thursday |
HH |
2-digit hour in 24-hour clock (00-23) |
16 |
hh |
2-digit hour in 12-hour clock (01-12) |
04 |
mm |
2-digit minute (00-59) |
45 |
ss |
2-digit second (00-59) |
12 |
fff |
Milliseconds padded to 3 digits | 258 |
tt |
AM / PM designator | PM |
K |
Time zone offset / UTC indicator | +02:00 or Z |
$LogStamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$Iso8601 = Get-Date -Format "o"
$DisplayDate = Get-Date -Format "dddd, MMMM dd, yyyy"
Write-Output "Log Timestamp : $LogStamp"
Write-Output "ISO Standard : $Iso8601"
Write-Output "Display Date : $DisplayDate"pwsh ./format-date-examples.ps1Log Timestamp : 2026-09-27_21-47-00
ISO Standard : 2026-09-27T21:47:00.8570272+02:00
Display Date : Sunday, September 27, 2026Using .ToString() on a stored DateTime object:
(Get-Date).ToString("dddd, MMMM dd, yyyy")Sunday, September 27, 2026Date Arithmetic
DateTime objects provide built-in methods for date and time calculations, such as calculating expiration dates or past time intervals.
Adding and Subtracting Intervals
Because DateTime objects are immutable, their arithmetic methods return a new DateTime instance representing the calculated point in time:
| Method | Description |
|---|---|
.AddYears(int) |
Adds or subtracts whole years. |
.AddMonths(int) |
Adds or subtracts whole months. |
.AddDays(double) |
Adds (or subtracts, via negative numbers) calendar days. |
.AddHours(double) |
Adds fractional hours. |
.AddMinutes(double) |
Adds fractional minutes. |
.AddSeconds(double) |
Adds fractional seconds. |
.AddMilliseconds(double) |
Adds fractional milliseconds. |
$today = Get-Date
$nextWeek = $today.AddDays(7)
$twoHoursAgo = $today.AddHours(-2)
Write-Output "Today: $($today.ToString('yyyy-MM-dd'))"
Write-Output "Next Week: $($nextWeek.ToString('yyyy-MM-dd'))"
Write-Output "Two Hours Ago: $($twoHoursAgo.ToString('yyyy-MM-dd HH:mm'))"where:
.AddDays(7)returns a newDateTimeobject 7 days in the future..AddHours(-2)subtracts time by passing a negative value.- The original
$todayvariable remains unchanged, sinceDateTimeis a value type.
./date-math.ps1Today: 2026-09-27
Next Week: 2026-10-04
Two Hours Ago: 2026-09-27 19:47A second example calculating retention windows:
$Now = Get-Date
$PasswordExpires = $Now.AddDays(90)
$RetentionCutoff = $Now.AddDays(-14)
Write-Output "Expires: $($PasswordExpires.ToShortDateString())"
Write-Output "Cutoff: $($RetentionCutoff.ToShortDateString())"Expires: 1/22/2026
Cutoff: 10/10/2026Comparing Dates
Because DateTime objects encapsulate chronological points in time, you can compare them directly using PowerShell's relational operators (-lt, -gt, -le, -ge, -eq, -ne). The engine compares the actual timestamps rather than their string representations, so no string parsing is needed.
$deadline = Get-Date "2026-06-01"
$today = Get-Date
if ($today -gt $deadline) {
Write-Output "Deadline has passed."
} else {
Write-Output "Deadline is still upcoming."
}where -gt compares the two DateTime objects chronologically, just like comparing numbers.
./compare-dates.ps1Deadline is still upcoming.A second example using a warning threshold:
$CertificateExpiry = Get-Date "2026-11-01 00:00:00"
$WarningThreshold = (Get-Date).AddDays(30)
if ($CertificateExpiry -lt (Get-Date)) {
Write-Error "Certificate is expired!"
}
elseif ($CertificateExpiry -le $WarningThreshold) {
Write-Warning "Certificate expires soon: $CertificateExpiry"
}
else {
Write-Output "Certificate is valid."
}pwsh ./compare-dates-threshold.ps1WARNING: Certificate expires soon: 11/01/2026 00:00:00TimeSpan Objects
Subtracting one DateTime from another produces a System.TimeSpan object, representing the duration between the two points in time.
$start = Get-Date "2026-01-01"
$end = Get-Date "2026-03-14"
$duration = $end - $start
Write-Output $durationwhere:
$end - $startreturns aTimeSpanobject rather than a plain number.TimeSpanexposes properties like.Days,.Hours,.Minutes, and.TotalDays.
./timespan.ps1Days : 72
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 62208000000000
TotalDays : 72
TotalHours : 1728
TotalMinutes : 103680
TotalSeconds : 6220800
TotalMilliseconds : 6220800000Inspecting the object type:
$StartTime = Get-Date "2026-10-24 08:00:00"
$EndTime = Get-Date "2026-10-24 10:30:15"
$Duration = $EndTime - $StartTime
$Duration.GetType().FullNameSystem.TimeSpanThe New-TimeSpan Cmdlet
You can also construct a TimeSpan directly using New-TimeSpan, useful for adding a specific duration to a date or representing a fixed interval:
$span = New-TimeSpan -Days 3 -Hours 12
(Get-Date) + $spanThursday, October 1, 2026 9:52:01 AMA maintenance-window example:
$MaintenanceWindow = New-TimeSpan -Hours 2 -Minutes 30
$MaintenanceWindowDays : 0
Hours : 2
Minutes : 30
Seconds : 0
Milliseconds : 0
Ticks : 90000000000
TotalDays : 0.104166666666667
TotalHours : 2.5
TotalMinutes : 150
TotalSeconds : 9000
TotalMilliseconds : 9000000where:
New-TimeSpanbuilds aTimeSpanobject from specified units (-Days,-Hours,-Minutes, etc.).- Adding a
TimeSpanto aDateTimeproduces a new, shiftedDateTime.
Component Properties vs. Total Properties
When reading values from a TimeSpan object, make sure to distinguish between component properties and total properties:
- Component Properties (
.Days,.Hours,.Minutes,.Seconds): Represent the remaining fraction of that time unit within the larger interval. For a duration of 2 hours and 30 minutes,.Hoursreturns2. - Total Properties (
.TotalDays,.TotalHours,.TotalMinutes,.TotalSeconds): Represent the entire duration expressed as a single floating-point number. For the same duration,.TotalHoursreturns2.5and.TotalMinutesreturns150.
Practical Example: Automated File Retention and Age Audit
The following script scans a directory for files, calculates the age of each file using TimeSpan arithmetic, and flags files that exceed a defined retention threshold:
param (
[string]$TargetFolder = "$env:TEMP",
[int]$RetentionDays = 30
)
$CurrentTime = Get-Date
$OldestAllowed = $CurrentTime.AddDays(-$RetentionDays)
Get-ChildItem -Path $TargetFolder -File -ErrorAction SilentlyContinue |
Select-Object -First 4 |
ForEach-Object {
$FileAge = $CurrentTime - $_.LastWriteTime
[PSCustomObject]@{
FileName = $_.Name
LastModified = $_.LastWriteTime.ToString("yyyy-MM-dd HH:mm")
AgeInDays = [math]::Round($FileAge.TotalDays, 1)
ExceedsPolicy = ($_.LastWriteTime -lt $OldestAllowed)
ActionRequired = if ($_.LastWriteTime -lt $OldestAllowed) { "Purge" } else { "Retain" }
}
}where:
$CurrentTime.AddDays(-$RetentionDays)calculates the historical cutoff boundary.$_.LastWriteTimeretrieves theDateTimetimestamp metadata stored by the filesystem provider.$FileAge = $CurrentTime - $_.LastWriteTimeproduces aTimeSpanobject.[math]::Round($FileAge.TotalDays, 1)rounds the total elapsed days to one decimal place.$_.LastWriteTime -lt $OldestAlloweduses direct date comparison to flag out-of-policy files.
Execute the script from the console:
pwsh ./audit-file-retention.ps1 -RetentionDays 7FileName : .ses
LastModified : 2026-09-27 16:41
AgeInDays : 0.2
ExceedsPolicy : False
ActionRequired : Retain
FileName : 256cb870-fe9d-44ba-97f1-3d3eb570c482.tmp
LastModified : 2026-09-27 16:42
AgeInDays : 0.2
ExceedsPolicy : False
ActionRequired : Retain
FileName : mat-debug-5124.log
LastModified : 2026-09-27 11:18
AgeInDays : 0.4
ExceedsPolicy : False
ActionRequired : Retain
FileName : mat-debug-7512.log
LastModified : 2026-09-27 11:30
AgeInDays : 0.4
ExceedsPolicy : False
ActionRequired : Retain