DateFormat UnitTest 在 Jenkins 中失败但在本地失败
DateFormat UnitTest fails in Jenkins but not locally
我对一个服务进行了单元测试,当我执行 Jenkins 作业时,每个测试方法都正确通过,只有一个除外。
但是这个测试方法在我的机器上工作,使用 Eclipse 和使用 mvn
命令。
// TARGET_RUN_DATE_OF_YEAR = "2018-01-01"
@Test
public void dateToTimestamp() {
Service service = getService();
String df = "YYYY-MM-dd";
String invalid = "INVALID";
// Check success
Timestamp timestamp = service.dateToTimestamp(TARGET_RUN_DATE_OF_YEAR, df);
Assert.assertEquals(service.getTodayTimestamp(), timestamp); // <-- Fail here
// Check failure
Assert.assertNull(service.dateToTimestamp(TARGET_RUN_DATE_OF_YEAR, invalid));
Assert.assertNull(service.dateToTimestamp(invalid, df));
}
服务有多种方法:
getTodayTimestamp
给今天的Timestamp,这个方法经过测试,在我的机器和Jenkins上都有效。
dateToTimestamp
将日期和日期格式作为字符串,returns 将日期作为时间戳,此方法无效。
服务中的dateToTimestamp
方法:
private Timestamp dateToTimestamp(String date, DateFormat df) throws ParseException {
return new Timestamp(df.parse(date).getTime());
}
@Override
public Timestamp dateToTimestamp(String date, String dateFormatString) {
try {
DateFormat df = new SimpleDateFormat(dateFormatString);
return dateToTimestamp(date, df);
} catch (Exception e) {
log.warn("Exception during conversion of date to timestamp, exception : {}", e);
return null;
}
}
正如我之前所说,测试在我的电脑上完美运行,但在 Jenkins 上却不行(向此方法添加 @Ignore
注释,使工作成功)。
启动作业时,出现此错误:
Failed tests: dateToTimestamp(com.test.service.ServiceImplTest): expected:<2018-01-01 00:00:00.0> but was:<2017-12-31 00:00:00.0>
我可以保证的是,即使在 Jenkins 中,dateToTimestamp
方法也采用参数 TARGET_RUN_DATE_OF_YEAR
,即 "2018-01-01"
和日期格式字符串 "YYYY-MM-dd"
。但仍然 returns 2017-12-31 00:00:00.0
作为时间戳。
有什么想法吗?
java.time
我假设您想要一个 Timestamp
用于您的 SQL 数据库。不要在 2019 年使用 Timestamp
。class 设计不佳且早已过时。
- 如果 SQL 端的数据类型是
timestamp with time zone
(时间戳应该是),请在 Java. 中使用 OffsetDateTime
- 如果在 SQL 方面您只需要
timestamp
(不带时区),请在 Java 中使用 LocalDateTime
。
代码示例:
String dateString = "2018-01-01";
OffsetDateTime odt = LocalDate.parse(dateString)
.atStartOfDay()
.atOffset(ZoneOffset.UTC);
System.out.println(odt);
输出为:
2018-01-01T00:00Z
现在您可以将 OffsetDateTime
传递给 JDBC,方法如下:
yourPreparedStatement.setObject(4, odt);
你的代码出了什么问题?
我相信您同时遇到了两个问题:
- 在您的格式模式字符串中使用大写
YYYY
是不正确的。大写 Y
用于基于周的年份,仅对周数有用。使用旧的和麻烦的 SimpleDateFormat
你需要小写的 y
作为年份。
- (The JVMs on) 你的机器和 Jenkins 服务器有不同的默认语言环境。
演示:
String dateString = "2018-01-01";
String dateFormatString = "YYYY-MM-dd"; // Incorrect format pattern string
DateFormat df = new SimpleDateFormat(dateFormatString);
System.out.println(df.parseObject(dateString));
我电脑上的输出(丹麦语言环境,Europe/Copenhagen 时区):
Mon Jan 01 00:00:00 CET 2018
但是,如果我首先这样做:
Locale.setDefault(Locale.US);
——那么上面代码片段的输出是不同的,即:
Sun Dec 31 00:00:00 CET 2017
发生的事情是 SimpleDateFormat
放弃了根据基于周的年、月和日确定确切日期,而是只为您提供基于年的周的第一个日期。这是 SimpleDateFormat
的典型行为,给你一个不可能正确的结果,但仍然假装一切都很好。在某些地区,一周从星期一开始,您会得到 Mon Jan 01,这 巧合 与您的字符串一致。在其他地区,例如美国,一周从星期日开始,因此您得到的是前一年的 12 月 31 日星期日。
Link
- Oracle tutorial: Date Time 解释如何使用 java.time.
- 有关年份大写
Y
的相关问题:java parsing string to date
我对一个服务进行了单元测试,当我执行 Jenkins 作业时,每个测试方法都正确通过,只有一个除外。
但是这个测试方法在我的机器上工作,使用 Eclipse 和使用 mvn
命令。
// TARGET_RUN_DATE_OF_YEAR = "2018-01-01"
@Test
public void dateToTimestamp() {
Service service = getService();
String df = "YYYY-MM-dd";
String invalid = "INVALID";
// Check success
Timestamp timestamp = service.dateToTimestamp(TARGET_RUN_DATE_OF_YEAR, df);
Assert.assertEquals(service.getTodayTimestamp(), timestamp); // <-- Fail here
// Check failure
Assert.assertNull(service.dateToTimestamp(TARGET_RUN_DATE_OF_YEAR, invalid));
Assert.assertNull(service.dateToTimestamp(invalid, df));
}
服务有多种方法:
getTodayTimestamp
给今天的Timestamp,这个方法经过测试,在我的机器和Jenkins上都有效。dateToTimestamp
将日期和日期格式作为字符串,returns 将日期作为时间戳,此方法无效。
服务中的dateToTimestamp
方法:
private Timestamp dateToTimestamp(String date, DateFormat df) throws ParseException {
return new Timestamp(df.parse(date).getTime());
}
@Override
public Timestamp dateToTimestamp(String date, String dateFormatString) {
try {
DateFormat df = new SimpleDateFormat(dateFormatString);
return dateToTimestamp(date, df);
} catch (Exception e) {
log.warn("Exception during conversion of date to timestamp, exception : {}", e);
return null;
}
}
正如我之前所说,测试在我的电脑上完美运行,但在 Jenkins 上却不行(向此方法添加 @Ignore
注释,使工作成功)。
启动作业时,出现此错误:
Failed tests: dateToTimestamp(com.test.service.ServiceImplTest): expected:<2018-01-01 00:00:00.0> but was:<2017-12-31 00:00:00.0>
我可以保证的是,即使在 Jenkins 中,dateToTimestamp
方法也采用参数 TARGET_RUN_DATE_OF_YEAR
,即 "2018-01-01"
和日期格式字符串 "YYYY-MM-dd"
。但仍然 returns 2017-12-31 00:00:00.0
作为时间戳。
有什么想法吗?
java.time
我假设您想要一个 Timestamp
用于您的 SQL 数据库。不要在 2019 年使用 Timestamp
。class 设计不佳且早已过时。
- 如果 SQL 端的数据类型是
timestamp with time zone
(时间戳应该是),请在 Java. 中使用 - 如果在 SQL 方面您只需要
timestamp
(不带时区),请在 Java 中使用LocalDateTime
。
OffsetDateTime
代码示例:
String dateString = "2018-01-01";
OffsetDateTime odt = LocalDate.parse(dateString)
.atStartOfDay()
.atOffset(ZoneOffset.UTC);
System.out.println(odt);
输出为:
2018-01-01T00:00Z
现在您可以将 OffsetDateTime
传递给 JDBC,方法如下:
yourPreparedStatement.setObject(4, odt);
你的代码出了什么问题?
我相信您同时遇到了两个问题:
- 在您的格式模式字符串中使用大写
YYYY
是不正确的。大写Y
用于基于周的年份,仅对周数有用。使用旧的和麻烦的SimpleDateFormat
你需要小写的y
作为年份。 - (The JVMs on) 你的机器和 Jenkins 服务器有不同的默认语言环境。
演示:
String dateString = "2018-01-01";
String dateFormatString = "YYYY-MM-dd"; // Incorrect format pattern string
DateFormat df = new SimpleDateFormat(dateFormatString);
System.out.println(df.parseObject(dateString));
我电脑上的输出(丹麦语言环境,Europe/Copenhagen 时区):
Mon Jan 01 00:00:00 CET 2018
但是,如果我首先这样做:
Locale.setDefault(Locale.US);
——那么上面代码片段的输出是不同的,即:
Sun Dec 31 00:00:00 CET 2017
发生的事情是 SimpleDateFormat
放弃了根据基于周的年、月和日确定确切日期,而是只为您提供基于年的周的第一个日期。这是 SimpleDateFormat
的典型行为,给你一个不可能正确的结果,但仍然假装一切都很好。在某些地区,一周从星期一开始,您会得到 Mon Jan 01,这 巧合 与您的字符串一致。在其他地区,例如美国,一周从星期日开始,因此您得到的是前一年的 12 月 31 日星期日。
Link
- Oracle tutorial: Date Time 解释如何使用 java.time.
- 有关年份大写
Y
的相关问题:java parsing string to date