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

Jenkins Groovy中Shell命令转换时间为秒始终返回相同值问题

Jenkins Groovy流水线时间转换问题排查

问题代码

用户编写的Groovy脚本化流水线代码:

def time1     = sh(script: 'date -u +"%Y-%m-%dT%H:%M:%S+00:00"', returnStdout: true).trim()
def time1_sec = sh(script: 'date -d "$time1" +%s', returnStdout: true).trim()
sleep(time: 30, unit: 'SECONDS')
def time2     = sh(script: 'date -u +"%Y-%m-%dT%H:%M:%S+00:00"', returnStdout: true).trim()
def time2_sec = sh(script: 'date -d "$time2" +%s', returnStdout: true).trim()

异常现象

控制台日志显示time1_sec和time2_sec返回相同值1709164800,且从日志可见执行date -d命令时未传入时间参数:

11:35:12  [Pipeline] sh
11:35:13  + date -u +%Y-%m-%dT%H:%M:%S+00:00
11:35:13  [Pipeline] sh
11:35:13  + date -d  +%s
11:35:13  [Pipeline] sleep
11:35:13  Sleeping for 30 sec
11:35:43  [Pipeline] sh
11:35:44  + date -u +%Y-%m-%dT%H:%M:%S+00:00
11:35:44  [Pipeline] sh
11:35:45  + date -d  +%s
11:35:45  [Pipeline] echo
11:35:45  time1    : 2024-02-29T16:35:13+00:00
11:35:45  [Pipeline] echo
11:35:45  time2    : 2024-02-29T16:35:44+00:00
11:35:45  [Pipeline] echo
11:35:45  time1_sec: 1709164800
11:35:45  [Pipeline] echo
11:35:45  time2_sec: 1709164800

而在Linux终端执行相同逻辑的Shell脚本可得到预期的不同结果:

#!/bin/bash
# Script name: date-time-2-seconds.sh

time1=$(date -u +"%Y-%m-%dT%H:%M:%S+00:00")
time1_sec=$(date -d "$time1" +%s)
sleep 30
time2=$(date -u +"%Y-%m-%dT%H:%M:%S+00:00")
time2_sec=$(date -d "$time2" +%s)

echo "time1    : ${time1}"
echo "time2    : ${time2}"
echo "time1_sec: ${time1_sec}"
echo "time2_sec: ${time2_sec}"

执行输出:

$ ./date-time-2-seconds.sh
time1    : 2024-02-29T16:52:58+00:00
time2    : 2024-02-29T16:53:28+00:00
time1_sec: 1709225578
time2_sec: 1709225608

问题原因

Groovy中单引号字符串不会进行变量插值,你编写的'date -d "$time1" +%s'里的$time1是Shell层面的变量,但每个sh步骤都会启动全新的Shell进程,该进程中未定义time1变量,因此Shell执行时$time1会被解析为空字符串,最终执行的命令变成date -d +%s。

当date -d未传入有效时间参数时,会返回一个固定的默认时间戳(如你看到的1709164800),导致两次结果相同。

修复方案

方案1:使用Groovy双引号实现变量插值

把Shell命令用Groovy双引号包裹,让Groovy先将$time1替换为实际值,再传递给Shell执行:

def time1     = sh(script: 'date -u +"%Y-%m-%dT%H:%M:%S+00:00"', returnStdout: true).trim()
def time1_sec = sh(script: "date -d '$time1' +%s", returnStdout: true).trim()
sleep(time: 30, unit: 'SECONDS')
def time2     = sh(script: 'date -u +"%Y-%m-%dT%H:%M:%S+00:00"', returnStdout: true).trim()
def time2_sec = sh(script: "date -d '$time2' +%s", returnStdout: true).trim()

这里用单引号包裹时间字符串,避免Groovy转义问题,同时确保Shell能正确解析时间格式。

方案2:合并Shell命令,减少进程调用

一次Shell调用同时获取格式化时间和时间戳,避免跨Shell传递变量的问题,效率更高:

// 一次调用拿到格式化时间和时间戳,用空格分隔
def time1_data = sh(script: 'date -u +"%Y-%m-%dT%H:%M:%S+00:00 %s"', returnStdout: true).trim().split()
def time1 = time1_data[0]
def time1_sec = time1_data[1]

sleep(time: 30, unit: 'SECONDS')

def time2_data = sh(script: 'date -u +"%Y-%m-%dT%H:%M:%S+00:00 %s"', returnStdout: true).trim().split()
def time2 = time2_data[0]
def time2_sec = time2_data[1]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 00:27:18