17370845950

如何获取数组中最近的到期日期(排除无效日期)

本文介绍如何从包含多个商品有效期的 json 数组中,准确筛选出最近的有效期项(即最小合法日期),自动忽略 `"0000-00"` 等无效值,并返回完整数据对象。

在实际业务开发中(如库存管理、批次追踪等场景),常需从一组带 expiration 字段的 JSON 数据中找出最近到期的商品项。注意:“最近”在此语境下指时间上最早发生的合法到期日(例如 2025-03 比 2025-02 更近),同时必须排除形如 "0000-00" 的占位或无效日期。

原始代码存在两个关键问题:

  1. min($item->expiration) 无法跨循环比较——每次迭代都用单个字符串调用 min(),结果恒为该字符串本身;
  2. 字符串直接比较 "2025-03" 和 "2025-02" 虽然可行,但依赖固定格式且缺乏健壮性(如 "2025-12" 与 "2025-01" 的字典序比较仍正确,但不推荐依赖);更可靠的方式是转换为时间戳进行数值比较。

以下是经过优化的专业实现:

/**
 * 从 JSON 格式的商品数组中获取最近到期的有效项
 * @param string $jsonItems JSON 字符串,格式如: '[{"expiration":"2025-03","quantity":50}, ...]'
 * @return array|null 最近到期的项(关联数组),若无有效项则返回 null
 */
function getNearestExp(string $jsonItems): ?array
{
    $items = json_decode($jsonItems, associative: true);
    if (json_last_error() !== JSON_ERROR_NONE || !is_array($items)) {
        throw new InvalidArgumentException('Invalid JSON input');
    }

    $validItems = [];
    foreach ($items as $item) {
        // 跳过缺失字段或无效 expiration 值
        if (!isset($item['expiration']) || $item['expiration'] === '0000-00') {
            continue;
        }

        // 尝试解析为年-月格式的时间戳(默认当月第一天)
        $timestamp = strtotime($item['expiration'] . '-01');
        if ($timestamp === false) {
            continue; // 跳过无法解析的日期格式
        }

        $validItems[$timestamp] = $item;
    }

    if (empty($validItems)) {
        return null;
    }

    ksort($validItems); // 按时间戳升序排列 → 最早到期项在首位
    return array_values($validItems)[0];
}

// 使用示例:
$itemsJson = '[{"expiration": "0000-00", "quantity": -50}, {"expiration": "2025-02", "quantity": 100}, {"expiration": "2025-03", "quantity": 50}]';
$result = getNearestExp($itemsJson);
var_dump($result); // 输出: ["expiration" => "2025-03", "quantity" => 50]

关键优势说明:

  • 使用 strtotime($item['expiration'] . '-01') 确保 YYYY-MM 格式被正确解析为时间戳(补 -01 避免解析失败);
  • 采用 ksort() 对时间戳键排序,逻辑清晰且性能良好;
  • 增加了 JSON 解析错误、空数组、非法日期等边界情况处理;
  • 返回标准关联数组(非对象),便于后续数组操作或 JSON 序列化。

⚠️ 注意事项:

  • 若数据中存在 YYYY-MM-DD 完整格式,本函数同样兼容;
  • 不建议直接字符串比较(如 min(array_column($items, 'expiration'))),因 '2025-12' > '2025-01' 在字典序中为真,但时间上错误;
  • 生产环境建议配合数据库 DATE 或 VARCHAR 字段的索引优化,高频查询时可预计算并缓存最近到期项。

通过此方法,你不仅能精准获取 2025-03 这一最近到期项,还能确保代码具备可维护性、鲁棒性与扩展性。