PAYATHON 2026

alipay.trade.page.pay 的 time_expire 应传入哪个时区?

支付小周

结论

alipay.trade.page.pay 的 time_expire 应传中国标准时间,也就是东八区时间(UTC+8),不能直接传 UTC 时间。

参数格式为:

yyyy-MM-dd HH:mm:ss

例如,订单需要在北京时间 2026-09-09 18:30:00 过期,应传:

2026-09-09 18:30:00

参数值不包含 Z、+08:00 等时区标识。调用方需要先将时间转换为 Asia/Shanghai 时区,再按指定格式生成字符串。

为什么不能直接传 UTC 时间

time_expire 表示一个绝对过期时间,但它使用的是不带时区信息的日期字符串。支付宝无法通过参数内容判断调用方传入的是 UTC、服务器本地时间还是其他时区的时间。

直接格式化 UTC 时间并传入,可能导致 8 小时的偏差。例如:

UTC 时间:      2026-09-09 10:30:00
北京时间:     2026-09-09 18:30:00

如果订单原定于北京时间 18

过期,实际传入的却是:

2026-09-09 10:30:00

支付宝会按东八区时间处理这个值,订单可能提前 8 小时过期。

正确处理方式

无论应用服务器部署在哪个地区,都应显式指定 Asia/Shanghai,不要依赖操作系统、JVM 或 PHP 运行环境的默认时区。

处理步骤如下:

  1. 获取当前时间或业务指定的过期时间。
  2. 将其转换到 Asia/Shanghai 时区。
  3. 按 yyyy-MM-dd HH:mm:ss 格式输出。
  4. 把生成的字符串赋值给 time_expire。

Java 示例

下面的代码将订单过期时间设为当前时间之后 30 分钟:

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

ZoneId alipayZone = ZoneId.of("Asia/Shanghai");
DateTimeFormatter formatter =
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

String timeExpire = ZonedDateTime.now(alipayZone)
        .plusMinutes(30)
        .format(formatter);

AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();

AlipayTradePagePayModel model = new AlipayTradePagePayModel();
model.setOutTradeNo("ORDER_202609090001");
model.setTotalAmount("100.00");
model.setSubject("测试订单");
model.setProductCode("FAST_INSTANT_TRADE_PAY");
model.setTimeExpire(timeExpire);

request.setBizModel(model);

如果业务系统内部统一使用 UTC 保存时间,需要先转换时区:

import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

Instant expireInstant = Instant.now().plusSeconds(30 * 60);

String timeExpire = expireInstant
        .atZone(ZoneId.of("Asia/Shanghai"))
        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

PHP 示例

<?php

$expireTime = new DateTime('now', new DateTimeZone('Asia/Shanghai'));
$expireTime->modify('+30 minutes');

$timeExpire = $expireTime->format('Y-m-d H:i:s');

$bizContent = [
    'out_trade_no' => 'ORDER_202609090001',
    'total_amount' => '100.00',
    'subject' => '测试订单',
    'product_code' => 'FAST_INSTANT_TRADE_PAY',
    'time_expire' => $timeExpire,
];

已有 UTC 时间时,可以显式转换:

<?php

$expireTime = new DateTime(
    '2026-09-09 10:30:00',
    new DateTimeZone('UTC')
);

$expireTime->setTimezone(new DateTimeZone('Asia/Shanghai'));

$timeExpire = $expireTime->format('Y-m-d H:i:s');
// 结果:2026-09-09 18:30:00

注意事项

  • 不要传入 ISO 8601 格式,例如 2026-09-09T18:30:00+08:00 或 2026-09-09T10:30:00Z。
  • 不要依赖服务器的默认时区。如果服务器运行在 UTC 环境中,直接格式化当前时间会产生偏差。
  • time_expire 表示绝对过期时间。如果需要使用相对有效期,应根据接口当前文档确认是否改用 timeout_express。
  • 如果同时传入 time_expire 和 timeout_express,应按支付宝当前接口文档规定的优先级处理。为避免歧义,通常只传其中一个。
  • 生成时间后,应确认它晚于当前北京时间,并为网络延迟和请求处理预留时间。
  • 如果对过期时间有严格要求,业务系统内部可使用时间戳或 UTC 保存时间,仅在组装支付宝请求参数时转换为 Asia/Shanghai。

备注:内容仅供参考。