🐛 Problem
Start-FinOpsCostExport converts its date parameters to UTC before truncating them to a day. For any positive UTC offset that moves the date back by one day, so the exported period is shifted:
# machine in UTC+01:00
Start-FinOpsCostExport -Name 'CostExport' -Scope $scope -StartDate '2026-01-01'
|
value |
| requested |
2026-01-01 |
| actually exported |
2025-12-31 through 2026-01-30 |
The user asks for January and gets 31 December added while 31 January is missing.
Reproducible without Azure:
$in = [datetime]'2026-01-01' # how PowerShell parses the parameter: local midnight
$in.ToUniversalTime().Date # -> 2025-12-31 in UTC+1/+2
🔍 Where
src/powershell/Public/Start-FinOpsCostExport.ps1 applies the same pattern in 7 places, e.g.:
# L102 -- backfill start
$StartDate = (Get-Date -Day 1 -Hour 0 -Minute 0 -Second 0 -Millisecond 0).ToUniversalTime().Date
# L119-L126 -- explicit start/end
$StartDate = $StartDate.ToUniversalTime().Date
$EndDate = $EndDate.ToUniversalTime().Date
$EndDate = $StartDate.ToUniversalTime().Date.AddMonths(1).AddDays(-1)
-Backfill is affected the same way: the first of the current month becomes the last day of the previous month, so each backfilled window is off by a day.
No other command in src/powershell/Public/ uses this pattern.
🌍 Why this has not shown up
The defect is asymmetric:
- Negative offsets (Americas): local midnight converts to a later hour on the same UTC day, so
.Date is unchanged. No visible effect.
- Positive offsets (Europe, Asia): local midnight converts to the previous UTC day. Off by one, always.
CI runs on UTC, so it never reproduces there.
🧪 The unit tests currently encode the behavior
Three tests in src/powershell/Tests/Unit/Start-FinOpsCostExport.Tests.ps1 fail on any machine east of UTC:
[-] Should call /run with default end date
[-] Should call /run for backfill
[-] Should adjust end date if it would be in the future
Expected Invoke-Rest ... to be called at least 1 times, but was called 0 times
They build their expected values with Get-Date -Month 1 -Day 1 -Hour 0 ... -AsUTC, which converts local midnight to UTC and lands on 31 December, and then compare against a format string with a hardcoded yyyy-01-01. Both sides shift, so the -ParameterFilter never matches.
This is worth calling out because "just fix the tests" would cement the product behavior. The tests are a symptom, not the defect.
🤔 Question before a fix
Are -StartDate / -EndDate meant to be calendar dates or instants?
The help text reads like calendar dates ("Day to start pulling the data for", "Last day to pull data for"), and Cost Management export periods are day-granular, which suggests the intended handling is to keep the day the caller named and not convert time zones:
$StartDate = [datetime]::SpecifyKind($StartDate.Date, [System.DateTimeKind]::Utc)
That is a behavior change for existing users at positive offsets (it would start exporting the day they actually asked for) and a no-op for everyone else, so it seems worth confirming the intent before changing it. Happy to submit a PR covering the command and the three tests together once the direction is confirmed.
🔧 Environment
- FinOps hub version: current
dev; the pattern is unchanged in v13 and v14
- PowerShell: 7.6.3 on Windows, machine time zone UTC+01:00 (UTC+02:00 during DST)
- Billing account type: not relevant — the shift happens before any API call
ℹ️ Additional context
Found while verifying the R15 release candidate end to end. The three failing tests are also the reason the local suite is not green outside the CI time zone; they are unrelated to the two workflow-pinning failures fixed by #2252.
🐛 Problem
Start-FinOpsCostExportconverts its date parameters to UTC before truncating them to a day. For any positive UTC offset that moves the date back by one day, so the exported period is shifted:The user asks for January and gets 31 December added while 31 January is missing.
Reproducible without Azure:
🔍 Where
src/powershell/Public/Start-FinOpsCostExport.ps1applies the same pattern in 7 places, e.g.:-Backfillis affected the same way: the first of the current month becomes the last day of the previous month, so each backfilled window is off by a day.No other command in
src/powershell/Public/uses this pattern.🌍 Why this has not shown up
The defect is asymmetric:
.Dateis unchanged. No visible effect.CI runs on UTC, so it never reproduces there.
🧪 The unit tests currently encode the behavior
Three tests in
src/powershell/Tests/Unit/Start-FinOpsCostExport.Tests.ps1fail on any machine east of UTC:They build their expected values with
Get-Date -Month 1 -Day 1 -Hour 0 ... -AsUTC, which converts local midnight to UTC and lands on 31 December, and then compare against a format string with a hardcodedyyyy-01-01. Both sides shift, so the-ParameterFilternever matches.This is worth calling out because "just fix the tests" would cement the product behavior. The tests are a symptom, not the defect.
🤔 Question before a fix
Are
-StartDate/-EndDatemeant to be calendar dates or instants?The help text reads like calendar dates ("Day to start pulling the data for", "Last day to pull data for"), and Cost Management export periods are day-granular, which suggests the intended handling is to keep the day the caller named and not convert time zones:
That is a behavior change for existing users at positive offsets (it would start exporting the day they actually asked for) and a no-op for everyone else, so it seems worth confirming the intent before changing it. Happy to submit a PR covering the command and the three tests together once the direction is confirmed.
🔧 Environment
dev; the pattern is unchanged in v13 and v14ℹ️ Additional context
Found while verifying the R15 release candidate end to end. The three failing tests are also the reason the local suite is not green outside the CI time zone; they are unrelated to the two workflow-pinning failures fixed by #2252.