I've made a unit-test of a Service, when I execute the Jenkins job, every test method pass correctly, except one.
But this test method, works on my machine, both with Eclipse and using the mvn
command.
// 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));
}
The Service have mulitple methods:
getTodayTimestamp
give today Timestamp, this method is tested, it works on my machine and on Jenkins.dateToTimestamp
takes a date and a dateFormat as Strings, and returns the date as a Timestamp, this method is the one not working.The dateToTimestamp
method in the Service:
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;
}
}
As I previously said, the test work perfectly on my pc, but not on Jenkins (adding the @Ignore
annotations to this method, makes the job successful).
When launching the job, I get this error:
Failed tests: dateToTimestamp(com.test.service.ServiceImplTest): expected:<2018-01-01 00:00:00.0> but was:<2017-12-31 00:00:00.0>
What I can assure, is that even in Jenkins, the dateToTimestamp
method takes the parameters TARGET_RUN_DATE_OF_YEAR
, which is "2018-01-01"
and the dateFormart String as "YYYY-MM-dd"
. But still returns 2017-12-31 00:00:00.0
as Timestamp.
Any ideas?
I am assuming that you wanted a Timestamp
for use with your SQL database. Don’t use Timestamp
for that in 2019. That class is poorly designed and long outdated.
timestamp with time zone
(which it should be for a timestamp), use OffsetDateTime
in Java.timestamp
(without time zone), use LocalDateTime
in Java.Code example:
String dateString = "2018-01-01";
OffsetDateTime odt = LocalDate.parse(dateString)
.atStartOfDay()
.atOffset(ZoneOffset.UTC);
System.out.println(odt);
Output is:
2018-01-01T00:00Z
Now you can pass your OffsetDateTime
to JDBC using something like:
yourPreparedStatement.setObject(4, odt);
I believe that you are experiencing the combination of two issues:
YYYY
in your format pattern string is incorrect. Uppercase Y
is for week based year and only useful with a week number. With the old and troublesome SimpleDateFormat
you would have needed lowercase y
for year.To demonstrate:
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));
Output on my computer (Danish locale, Europe/Copenhagen time zone):
Mon Jan 01 00:00:00 CET 2018
However if I first do this:
Locale.setDefault(Locale.US);
— then the output from the above snippet is different, namely:
Sun Dec 31 00:00:00 CET 2017
What happens is that SimpleDateFormat
gives up on determining an exact date from week based year, month and day of month and instead just gives you the first date of the week based year. It’s typical behaviour of SimpleDateFormat
to give you a result that cannot be right and nevertheless pretend that all is well. In some locales the week begins on Monday, and you get Mon Jan 01, which coincidentally agrees with your string. In other locales, such as the US, the week starts on Sunday, so instead you get Sun Dec 31 of the previous year.
Y
for year: java parsing string to date