PAYATHON 2026

SoftLayer API 返回时间与实际计费周期如何对应?

支付阿杰

明确结论

账单周期应以 billingItem.cycleStartDate 和相邻账单的实际周期边界为准,不能只按自然月零点推算。

示例中的 invoice.createDate 与 billingItem.cycleStartDate 完全一致:

2016-05-01T00:36:56-05:00

这通常说明 recurring invoice 生成时,该 billing item 进入了新的计费周期。上一周期在这个时间点结束,下一周期也从这里开始。

因此,实际周期边界更可能是:

上一周期结束:2016-05-01T00:36:56-05:00
下一周期开始:2016-05-01T00:36:56-05:00

不能假定账单只统计到 2016-04-30T23:59:59。也不能因为 latestBillDate 是 2016-05-01T00:00:00-05:00,就认定实际计费边界一定在午夜。

不过,hourly usage 通常按计费小时或平台规定的计量单位结算,并非严格按前一秒和下一秒切分。时间戳表示周期边界,不代表费用一定按秒计算。

三个时间字段分别表示什么

latestBillDate

"latestBillDate": "2016-05-01T00:00:00-05:00"

它表示账户最近一次出账对应的 billing date,更接近账务日期或账单周年日,不一定是后台完成账单生成的准确时间。

invoice.createDate

"createDate": "2016-05-01T00:36:56-05:00"

这是 invoice 记录实际创建的时间。账单任务可能需要排队和处理,因此该时间比 billing date 晚几十分钟并不反常。

billingItem.cycleStartDate

"cycleStartDate": "2016-05-01T00:36:56-05:00"

这是该 billing item 当前计费周期的开始时间。它与 invoice 的 createDate 相同,说明这次开票也触发了该项目的周期滚动。

这几个字段各有用途,不能互相替代:

  • latestBillDate 表示账务日期。
  • invoice.createDate 表示 invoice 对象的创建时间。
  • billingItem.cycleStartDate 表示具体计费项目的周期起点。

如何确认某笔费用属于哪个周期

不能只看账户级字段,还要检查 invoice item 和 billing item。可以按下面的顺序核对:

  1. 获取当前 recurring invoice 的 createDate。
  2. 获取对应 billing item 的 cycleStartDate。
  3. 获取上一张 recurring invoice 的创建时间。
  4. 查看 invoice item 中的 usage、小时数、费用和描述字段。
  5. 对照设备的启用、取消或暂停时间。

可以通过 object mask 一次获取这些字段:

GET https://api.softlayer.com/rest/v3/SoftLayer_Account/getLatestRecurringInvoice.json?objectMask=mask[
    id,
    createDate,
    closedDate,
    invoiceTopLevelItems[
        id,
        description,
        hourlyRecurringFee,
        recurringFee,
        usageCharge,
        billingItem[
            id,
            createDate,
            cancellationDate,
            cycleStartDate,
            currentHourlyCharge
        ]
    ]
]

可用字段会受到对象类型和 API 返回权限的影响。如果某个字段没有返回,应继续查询相应的 SoftLayer_Billing_Invoice、SoftLayer_Billing_Invoice_Item 或 SoftLayer_Billing_Item 对象,不能因此认定该字段的值为零。

核对相邻账单时,可以把周期写成半开区间:

[previousCycleStartDate, currentCycleStartDate)
[currentCycleStartDate, nextCycleStartDate)

这样可以避免同一个时间点被两个周期重复计算。SoftLayer 内部如何处理小时边界、部分小时和月度上限,仍要以对应产品当时的计费规则和 invoice item 明细为准。

为什么不能按自然月直接计算

账户在每月 1 日出账,不代表所有费用都严格按以下区间计算:

2016-05-01T00:00:00
到
2016-05-31T23:59:59

账单日期、账单任务的运行时间和具体 billing item 的周期起点可能并不一致。以下情况也可能改变单个项目的计费区间:

  • 资源在周期中途开通或取消;
  • hourly item 转换为其他计费方式;
  • 账单处理延迟;
  • 补收、抵扣或调整项目;
  • 不同产品采用不同的小时取整规则;
  • API 时间戳使用不同 UTC offset。

示例中同时出现了 -06:00 和 -05:00:

2016-03-10T16:18:23-06:00
2016-05-01T00:36:56-05:00

这可能与夏令时切换有关。比较时间时,应解析 ISO 8601 offset,最好统一转换成 UTC,不能忽略时间戳末尾的时区偏移。

例如:

2016-05-01T00:36:56-05:00
=
2016-05-01T05:36:56Z

注意事项

invoice.createDate 与 billingItem.cycleStartDate 相同,可以用来判断周期是否在开票时滚动,但无法仅凭这一点确定每笔 hourly usage 的内部取整方式。准确金额仍要根据 invoice item 中记录的小时数、usage charge、调整项及对应产品的计费规则计算。

如果相邻 invoice 的周期时间无法连续对应,或根据 usage 明细算出的金额与账单不一致,应向 IBM Cloud Billing 支持提交以下信息:

  • Account ID;
  • Invoice ID;
  • Billing Item ID;
  • 相关资源 ID;
  • 相邻两张 invoice 的 createDate;
  • Billing item 的 cycleStartDate;
  • Invoice item 的费用及 usage 明细。

如果涉及真实扣费争议,支持团队可以查看 API 未公开的内部计量和账务记录。只根据账户级 API 时间戳,无法可靠复算全部小时费用。

备注:内容仅供参考。