You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置Mojo::XMLRPC以指定DateTime格式处理Mojo::Date?

Mojo::XMLRPC日期格式适配方案

问题背景

使用Mojo::XMLRPC时遇到两个日期格式相关问题:

  • 编码问题:encode_xmlrpc生成的<dateTime.iso8601>格式为2023-06-14T19:45:48Z,但业务需要无分隔符日期+带时区偏移的格式(如20230614T22:45:48+0300)
  • 解码问题:当输入的<dateTime.iso8601>值为20230608T12:00:00+0000时,解码报错,错误信息如下:

Garbage at end of string in strptime: +0000 at /usr/local/opt/perl/lib/perl5/5.36/darwin-thread-multi-2level/Time/Piece.pm line 598. Perhaps a format flag did not match the actual input? at /usr/local/opt/perl/lib/perl5/5.36/darwin-thread-multi-2level/Time/Piece.pm line 598

问题根源在于Mojo::XMLRPC默认的日期格式数组不包含%Y%m%dT%H:%M:%S%z这类带时区偏移的无分隔符格式,导致编码输出不符合要求,解码无法识别目标格式。

解决方法

方案一:猴子补丁(推荐,无需修改模块源码)

通过重写Mojo::XMLRPC的编码/解码逻辑,适配自定义日期格式,完整代码如下:

#!/usr/bin/env perl
use Mojo::XMLRPC qw[encode_xmlrpc decode_xmlrpc];
use Data::Dumper;
use Mojo::Date;
use Time::Piece;

# 重写编码逻辑:生成自定义日期格式
BEGIN {
  no warnings 'redefine';
  *Mojo::XMLRPC::_encode_value = sub {
    my ($value) = @_;

    if (ref $value eq 'Mojo::Date') {
      # 生成YYYYMMDDTHH:MM:SS+ZZZZ格式的日期字符串
      my $formatted = $value->strftime('%Y%m%dT%H:%M:%S%z');
      return "<dateTime.iso8601>$formatted</dateTime.iso8601>";
    }

    # 保留原有其他类型编码逻辑
    return Mojo::XMLRPC::_encode_value($value) unless ref $value;
    return '<array><data>' . join('', map { _encode_value($_) } @$value) . '</data></array>' if ref $value eq 'ARRAY';
    return '<struct>' . join('', map { '<member><name>' . Mojo::XMLRPC::_escape_xml($_) . '</name>' . _encode_value($value->{$_}) . '</member>' } sort keys %$value) . '</struct>' if ref $value eq 'HASH';
    return '<string>' . Mojo::XMLRPC::_escape_xml($value) . '</string>';
  };

  # 重写解码逻辑:支持解析带时区偏移的无分隔符日期
  *Mojo::XMLRPC::_decode_value = sub {
    my ($value) = @_;

    if ($value =~ /^<dateTime\.iso8601>(.+)<\/dateTime\.iso8601>$/) {
      my $dt_str = $1;
      my $date;

      # 先尝试原有格式解析
      eval { $date = Mojo::Date->new($dt_str) };
      # 原有格式失败时,尝试自定义格式解析
      if (!$date || $@) {
        eval {
          my $tp = Time::Piece->strptime($dt_str, '%Y%m%dT%H:%M:%S%z');
          $date = Mojo::Date->new($tp->epoch);
        };
      }

      die "Invalid dateTime.iso8601 value: $dt_str" unless $date;
      return $date;
    }

    # 保留原有其他类型解码逻辑
    return $1 if $value =~ /^<i4>(.+)<\/i4>$/ || $value =~ /^<int>(.+)<\/int>$/;
    return $1 if $value =~ /^<string>(.+)<\/string>$/;
    return $1 + 0 if $value =~ /^<double>(.+)<\/double>$/;
    return 1 if $value eq '<boolean>1</boolean>';
    return 0 if $value eq '<boolean>0</boolean>';
    return undef if $value eq '<nil/>';
    return [map { _decode_value($_) } $value =~ /<value>(.+?)<\/value>/sg] if $value =~ /^<array><data>(.+)<\/data><\/array>$/;
    return {map { /<name>(.+?)<\/name><value>(.+?)<\/value>/; $1 => _decode_value($2) } $value =~ /<member>(.+?)<\/member>/sg} if $value =~ /^<struct>(.+)<\/struct>$/;
    die "Unsupported XML-RPC value: $value";
  };
}

# 测试编码
my $e = encode_xmlrpc(call => 'TaregtMethod' => {originTimeStamp=>Mojo::Date->new(time)});
say STDERR Dumper($e);

# 测试解码
my $xml = <<'XML';
<?xml version="1.0" encoding="utf-8"?>
<methodResponse>
  <params>
    <param>
      <value>
        <struct>
          <member>
            <name>activationDate</name>
            <value>
              <dateTime.iso8601>20230608T12:00:00+0000</dateTime.iso8601>
            </value>
          </member>
        </struct>
      </value>
    </param>
  </params>
</methodResponse>
XML

my $d = decode_xmlrpc($xml);
say STDERR Dumper($d);

方案二:修改Mojo::XMLRPC模块源码(不推荐)

找到系统中Mojo/XMLRPC.pm文件,修改两个关键部分:

  1. 添加自定义日期格式到@time_formats数组:
# 原代码
my @time_formats = (
  '%Y-%m-%dT%H:%M:%SZ',
  '%Y-%m-%dT%H:%M:%S',
  '%Y-%m-%d'
);

# 修改后
my @time_formats = (
  '%Y-%m-%dT%H:%M:%SZ',
  '%Y-%m-%dT%H:%M:%S',
  '%Y-%m-%d',
  '%Y%m%dT%H:%M:%S%z'  # 新增格式
);
  1. 修改编码时的日期生成逻辑,使用strftime输出目标格式:
    找到编码Mojo::Date的代码段,替换为:
if (ref $value eq 'Mojo::Date') {
  return "<dateTime.iso8601>" . $value->strftime('%Y%m%dT%H:%M:%S%z') . "</dateTime.iso8601>";
}

注意:该方案会在模块更新后丢失修改,仅适合临时场景使用。


内容的提问来源于stack exchange,提问作者h q

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 00:37:57