Put events in a UTC window
Compare timestamps as instants, including offsets and exact time-window boundaries.
The same instant, different clocks
A timestamp ending in Z is expressed in UTC. An explicit offset such as +11:00 tells you how its clock differs from UTC. In this dataset, 20:02:00+11:00 and 09:02:00Z describe the same instant. Comparing their text alphabetically would give a misleading order.
Parse each value as [DateTimeOffset]. It retains the supplied offset and supports comparisons between instants. These fixtures always include an offset. In a real import, reject or explicitly interpret timestamps with no timezone instead of silently assuming your workstation's local time.
Define the edges
Use a half-open interval: include the start and exclude the end. An event at 09:00 belongs to [09:00,09:15); one at 09:15 belongs to the next window. Adjacent windows then avoid double counting their shared boundary.
$instant = [DateTimeOffset]::Parse('2026-10-12T20:02:00+11:00')
$instant.ToUniversalTime().ToString('o')
Keep the original timestamp beside your UTC representation. That makes the transformation reviewable and preserves what the export actually said. A normalised value helps sorting; it does not improve a source clock that was wrong.
The exercise includes successful and failed logons. Its question is about time only: do not carry the previous lesson's failed-logon filter into this task.
Go deeper
[DateTimeOffset]::Parse('2026-10-12T20:02:00+11:00').ToUniversalTime().ToString('o')
Put it into practice.
From auth.csv, emit every event in [2026-10-12T09:00:00Z, 2026-10-12T09:15:00Z). Each object needs RecordId, OriginalTime (the unchanged Time string), and UtcTime (an ISO 8601 string with UTC offset). Include all event types. Order does not matter.
See an explained solution
$start = [DateTimeOffset]::Parse('2026-10-12T09:00:00Z')
$end = [DateTimeOffset]::Parse('2026-10-12T09:15:00Z')
foreach ($event in Import-Csv '/home/user/auth.csv') {
$time = [DateTimeOffset]::Parse($event.Time)
if ($time -ge $start -and $time -lt $end) {
[pscustomobject]@{ RecordId=$event.RecordId; OriginalTime=$event.Time; UtcTime=$time.ToUniversalTime().ToString('o') }
}
}
DateTimeOffset comparisons account for each offset. The half-open condition includes A02, converts A03 correctly, and leaves A10 for the next window.