如何获取 Azure Subscription 的 Billing Cycle 日期
结论
仅靠旧版 Microsoft.Commerce/UsageAggregates 和 RateCard API,无法可靠获取订阅当前账单周期的开始和结束日期。这两个 API 分别用于查询用量和价格,不返回账单周期。
如果要计算当前账单周期内尚未结算的费用,建议使用 Azure Cost Management Query API,并将 timeframe 设为 BillingMonthToDate,不必自行推算周期日期。
如果需要明确的起止日期,应从订阅所属的计费账户、账单配置文件或发票周期中查询。具体使用哪个接口,取决于订阅采用的计费协议,例如 Microsoft Customer Agreement、Enterprise Agreement 或旧式 Microsoft Online Services Program。
直接查询当前账单周期费用
调用 Cost Management Query API:
POST https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.CostManagement/query?api-version={supported-api-version}
Authorization: Bearer {access-token}
Content-Type: application/json
请求体示例:
{
"type": "ActualCost",
"timeframe": "BillingMonthToDate",
"dataset": {
"granularity": "None",
"aggregation": {
"totalCost": {
"name": "Cost",
"function": "Sum"
}
}
}
}
如需查看每日费用,可改为:
{
"type": "ActualCost",
"timeframe": "BillingMonthToDate",
"dataset": {
"granularity": "Daily",
"aggregation": {
"totalCost": {
"name": "Cost",
"function": "Sum"
}
}
}
}
BillingMonthToDate 查询的是 Azure 识别的当前计费月份,比按自然月手动设置 reportedStartTime 和 reportedEndTime 更合适。
如需包含已经产生、但可能尚未计入最终发票的费用,可以根据账户类型和业务含义选择:
"type": "ActualCost"
或:
"type": "AmortizedCost"
AmortizedCost 会把预留实例、Savings Plan 等部分预付费用按使用周期摊销,因此不能直接视为最终应付金额。
获取明确的账单周期日期
账单周期通常属于计费账户或账单配置文件,而不是订阅本身。可以按以下步骤处理:
- 确认订阅采用的计费协议及其计费账户。
- 获取订阅与 billing account、billing profile 或 invoice section 的关联关系。
- 查询相应计费范围的账单周期或发票信息。
- 从返回结果中读取周期的开始和结束日期。
- 使用该日期范围查询 Cost Management 数据。
对于支持 Azure Billing API 的账户,可以在 Microsoft.Billing 提供程序下查询 billing periods 或 invoices。部分账户和 API 版本支持类似下面的资源路径:
GET https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{billingAccountName}/billingPeriods?api-version={supported-api-version}
实际资源层级中可能还包含 billingProfiles 或 invoiceSections。应先通过 Billing API 列出当前身份可以访问的 billing accounts,再根据返回的账户结构选择接口。不能假设所有订阅都支持同一条 URL。
旧式订阅曾提供订阅级 billing periods 预览接口,例如:
GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Billing/billingPeriods?api-version=2018-03-01-preview
这是旧预览模型中的接口,不适合作为新系统的通用实现。它是否仍适用于某个订阅,应以该订阅当前支持的资源提供程序和 API 版本为准。
C# 查询当前账单周期费用示例
下面的代码主要展示请求结构。身份验证和错误处理需要接入应用已有的实现:
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
string url =
$"https://management.azure.com/subscriptions/{subscriptionId}" +
$"/providers/Microsoft.CostManagement/query?api-version={apiVersion}";
string requestBody = """
{
"type": "ActualCost",
"timeframe": "BillingMonthToDate",
"dataset": {
"granularity": "None",
"aggregation": {
"totalCost": {
"name": "Cost",
"function": "Sum"
}
}
}
}
""";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
using var content = new StringContent(
requestBody,
Encoding.UTF8,
"application/json");
HttpResponseMessage response = await client.PostAsync(url, content);
string responseBody = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
Console.WriteLine(responseBody);
不要假设金额列在返回行中的位置固定。应先读取响应里的 properties.columns,根据列名确定 Cost、Currency 等字段的位置,再解析 properties.rows。
如果必须继续使用 Usage API
使用 UsageAggregates 时,应用必须自行提供 reportedStartTime 和 reportedEndTime。这些日期可以取自 Billing API 返回的账单周期,但不建议直接使用每月 1 日至月末,原因包括:
- 账单周期不一定与自然月完全一致。
- 周期可能由计费账户或 billing profile 决定。
- 时间字段通常按 UTC 处理,换算为本地时区时可能出现一天的边界误差。
- 延迟上报的用量可能在查询完成后继续出现。
- Usage API 计算的估算金额不等于最终发票金额。
示例中的变量名与 URL 内容恰好相反:requestRateCardAPIurl 实际指向 UsageAggregates,requestUsageAPIurl 实际指向 RateCard。建议修改变量名,以免后续混淆价格数据和用量数据。
注意事项
当前周期费用只能作为估算或累计成本,通常无法保证与最终发票完全一致。税费、抵扣、Azure Credit、退款、舍入、预留折扣、第三方 Marketplace 费用和延迟到达的用量,都可能使结算金额发生变化。
调用者除了需要订阅权限,还可能需要计费范围或成本管理数据的读取权限。即使可以读取订阅资源,也未必可以读取 billing account、发票或成本数据。
备注:内容仅供参考。
