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

DocuSign formDataRecipient返回日期非UTC 是否为隐藏设置问题?

DocuSign API formDataRecipient字段时区异常问题解答

问题概述

DocuSign API通常返回UTC时区的日期,但formDataRecipient字段中的所有日期都未以UTC格式返回,排查账户内所有时区设置调整后问题仍未解决。
实际返回示例:

11:28:05,271 INFO  [stdout] (default task-187) envelope.id:00fc8865-0daa-4657-ad80-a79355cf9857
11:28:05,271 INFO  [stdout] (default task-187) envelope.sentDateTime:2021-09-17T01:26:47.9300000Z
11:28:05,271 INFO  [stdout] (default task-187) envelope.deliveredDateTime:2021-09-17T01:26:57.7130000Z
11:28:05,271 INFO  [stdout] (default task-187) envelope.completedDateTime:2021-09-17T01:27:54.8200000Z
11:28:05,271 INFO  [stdout] (default task-187) formDataRecipient.signedTime:2021-09-17T08:27:54.8200000Z

可以看到formDataRecipient中的signedTime和信封完成时间戳差了7小时,并未返回UTC时间。
相关代码片段:

final Envelope envelope = envelopesApi.getEnvelope( credentials.getAccountId(), document.getEnvelopeId() );
final EnvelopeFormData formData = envelopesApi.getFormData( credentials.getAccountId(), document.getEnvelopeId() );
boolean hasClientFields = false;
boolean hasPartnerFields = false;
boolean clientSigned = false;
boolean partnerSigned = false;
Date clientSignedDate = null;
Date partnerSignedDate = null;
final String signerNameClient = getSignerNameClient( memberJson );
final String signerNamePartner = getSignerNamePartner( memberJson );
final SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ" );

System.out.println( "envelope.id:" + envelope.getEnvelopeId() );
System.out.println( "envelope.sentDateTime:" + envelope.getSentDateTime() );
System.out.println( "envelope.deliveredDateTime:" + envelope.getDeliveredDateTime() );
System.out.println( "envelope.completedDateTime:" + envelope.getCompletedDateTime() );
if ( formData != null ) {
    for ( final RecipientFormData formDataRecipient : CoreCollectionUtils.nullSafe( formData.getRecipientFormData() ) ) {
        if ( formDataRecipient != null && formDataRecipient.getFormData() != null && formDataRecipient.getName().equalsIgnoreCase( signerNameClient ) ) {
            hasClientFields = true;
            if ( formDataRecipient.getSignedTime() != null ) {
                clientSigned = true;
                // Docusign date format is missing the +/- before the offset.
                final String dateDocuSign = formDataRecipient.getSignedTime().substring( 0, 23 ) + "+" + formDataRecipient.getSignedTime().subSequence( 23, formDataRecipient.getSignedTime().length() );
                clientSignedDate = sdf.parse( dateDocuSign );
                System.out.println( "formDataRecipient.signedTime:" + formDataRecipient.getSignedTime() );
            }

            if ( formDataRecipient.getFormData() != null ) {
                formDataRecipient.getFormData().forEach( f -> {
                    if ( f.getName() != null && f.getName().equalsIgnoreCase( EnvelopeHelpers.FIELD_TFN_NAME ) ) {
                        memberJson.setTfn( f.getValue() );
                    }
                } );
            }
        } else if ( formDataRecipient != null && formDataRecipient.getFormData() != null && formDataRecipient.getName().equalsIgnoreCase( signerNamePartner ) ) {
            hasPartnerFields = true;
            if ( formDataRecipient.getSignedTime() != null ) {
                partnerSigned = true;
                // Docusign date format is missing the +/- before the offset.
                final String dateDocuSign = formDataRecipient.getSignedTime().substring( 0, 23 ) + "+" + formDataRecipient.getSignedTime().subSequence( 23, formDataRecipient.getSignedTime().length() );
                partnerSignedDate = sdf.parse( dateDocuSign );
            }

            if ( formDataRecipient.getFormData() != null ) {
                formDataRecipient.getFormData().forEach( f -> {
                    if ( f.getName() != null && f.getName().equalsIgnoreCase( EnvelopeHelpers.FIELD_TFN_NAME ) ) {
                        memberJson.getPartner().setTfn( f.getValue() );
                    }
                } );
            }
        }
    }
}

补充说明:提问者认为2021-09-17T01:27:54.8200000Z不是标准格式,标准格式应为2021-09-17T01:27:54.820+0000Z。

问题结论

  • formDataRecipient返回非UTC时间不属于隐藏设置问题,是DocuSign不同API端点的固有设计差异:envelopes端点返回的信封核心元数据(发送时间、送达时间、完成时间等)统一使用UTC时区,而formData端点下的收件人签名时间默认返回签名操作时用户客户端的本地时区,和账户时区设置无关。
  • 带Z后缀的时间格式符合ISO 8601标准,后缀Z本身就代表UTC零偏移,和2021-09-17T01:27:54.820+0000等价,不属于格式错误,无需额外拼接偏移符号。

修复方案

时区统一处理

可以直接用信封的completedDateTime作为签名完成的UTC时间,也可以对formDataRecipient.signedTime做时区偏移转换:根据实际返回的本地时间和UTC时间的差值,减去对应偏移量即可得到标准UTC时间。

时间解析优化

Java 8及以上版本可直接使用Instant类解析该格式时间,无需手动处理字符串:

// 直接解析带Z后缀的ISO 8601时间
Instant signedInstant = Instant.parse(formDataRecipient.getSignedTime());
Date clientSignedDate = Date.from(signedInstant);

低版本Java可引入joda-time库完成解析,避免自行截取字符串引发的格式错误。


内容的提问来源于stack exchange,提问作者Geoffrey Thomazeau

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 00:54:04