Skip to content

Timezone-related test failures in JsonNormalizerTest #83

@nileader

Description

@nileader

Description

GitHub Issue: Timezone-related test failures in JsonNormalizerTest

Problem Description:

The JsonNormalizerTest in the JToon project contains 4 test cases related to time types that fail in my UTC+8 timezones because they use hardcoded expected values, while JsonNormalizer uses the system default timezone when processing SQL time types.

Affected 4 Test Cases:

dev.toonformat.jtoon.normalizer.JsonNormalizerTest$TemporalTypes.testSQLTimeStamp(JsonNormalizerTest.java:357)

dev.toonformat.jtoon.normalizer.JsonNormalizerTest$TemporalTypes.testSQLTime(JsonNormalizerTest.java:348)

dev.toonformat.jtoon.normalizer.JsonNormalizerTest$TryNormalizeTemporal.givenGregorianCalendar_whenTryNormalizeTemporal_thenIsoStringNode(JsonNormalizerTest.java:1208)

dev.toonformat.jtoon.normalizer.JsonNormalizerTest$TryNormalizeTemporal.givenCalendar_whenTryNormalizeTemporal_thenIsoStringNode(JsonNormalizerTest.java:1194)

Problem Details:

Original failing test result:
#My timezone: UTC+8
#e.g. Result of runJsonNormalizerTest$TemporalTypes.testSQLTimeStamp

Expected:1970-01-21T11:40:19.274 
Actual:1970-01-21T18:40:19.274

org.opentest4j.AssertionFailedError: expected: <1970-01-21T11:40:19.274> but was: <1970-01-21T18:40:19.274>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:158)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:139)
	at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:201)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:184)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:179)
	at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1188)
	at dev.toonformat.jtoon.normalizer.JsonNormalizerTest$TemporalTypes.testSQLTimeStamp(JsonNormalizerTest.java:357)
Original failing test code:
        @Test
        @DisplayName("should convert java.sql.Timestamp to ISO formatted StringNode")
        void testSQLTimeStamp() {
            java.sql.Timestamp dateTime = new java.sql.Timestamp(1766419274);
            JsonNode result = JsonNormalizer.normalize(dateTime);
            assertTrue(result.isString());
            assertEquals("1970-01-21T11:40:19.274", result.asString());
        }

        @Test
        @DisplayName("should convert java.sql.Time to ISO formatted StringNode")
        void testSQLTime() {
            java.sql.Time time = new java.sql.Time(1766419274);
            JsonNode result = JsonNormalizer.normalize(time);
            assertTrue(result.isString());
            assertEquals("11:40:19", result.asString());
        }

        @Test
        @DisplayName("Given GregorianCalendar, When tryNormalizeTemporal is called, Then an ISO date StringNode is returned")
        void givenGregorianCalendar_whenTryNormalizeTemporal_thenIsoStringNode() throws Exception {
            // Given
            GregorianCalendar input = new GregorianCalendar(2017, Calendar.FEBRUARY, 16, 20, 22, 28);

            // When
            Object result = invokePrivateStatic("tryNormalizeTemporal", new Class[]{Object.class}, input);

            // Then
            assertInstanceOf(StringNode.class, result);
            assertEquals("2017-02-16T19:22:28Z", ((JsonNode) result).asString());
        }

        @Test
        @DisplayName("Given Calendar, When tryNormalizeTemporal is called, Then an ISO date StringNode is returned")
        void givenCalendar_whenTryNormalizeTemporal_thenIsoStringNode() throws Exception {
            // Given
            Calendar input = Calendar.getInstance();
            input.set(2017, Calendar.FEBRUARY, 16, 20, 22, 28);
            input.set(Calendar.MILLISECOND, 0);

            // When
            Object result = invokePrivateStatic("tryNormalizeTemporal", new Class[]{Object.class}, input);

            // Then
            assertInstanceOf(StringNode.class, result);
            assertEquals("2017-02-16T19:22:28Z", ((JsonNode) result).asString());
        }
Root Cause:

The JsonNormalizer's [tryNormalizeTemporal] method uses system default timezone for SQL time types:

} else if (value instanceof java.sql.Timestamp timestamp) {
    return formatTemporal(timestamp.toLocalDateTime(), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
} else if (value instanceof java.sql.Date date) {
    return formatTemporal(date.toLocalDate(), DateTimeFormatter.ISO_LOCAL_DATE);
} else if (value instanceof java.sql.Time time) {
    return formatTemporal(time.toLocalTime(), DateTimeFormatter.ISO_LOCAL_TIME);
} else if (value instanceof Date date) {
    return StringNode.valueOf(LocalDate.ofInstant(date.toInstant(), ZoneId.systemDefault()).toString());
}

Solution:

Modify the test cases to calculate expected values using the same timezone logic as the implementation, instead of using hardcoded UTC values.

Fix Applied:

All 4 test cases now calculate expected values using the same timezone-aware logic as the implementation, ensuring tests pass in any timezone.

Code Changes:

The tests use dynamic expected values:

        @Test
        @DisplayName("should convert java.sql.Timestamp to ISO formatted StringNode")
        void testSQLTimeStamp() {
            java.sql.Timestamp dateTime = new java.sql.Timestamp(1766419274);
            JsonNode result = JsonNormalizer.normalize(dateTime);
            assertTrue(result.isString());
            //assertEquals("1970-01-21T11:40:19.274", result.asString());
            // Instead of hardcoded "1970-01-21T11:40:19.274"
            String expected = dateTime.toLocalDateTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            assertEquals(expected, result.asString());
        }

I have already fixed this issue in my forked repository and can submit a pull request if desired. The fix ensures test portability across different timezone environments.

Files Modified:
  • src/test/java/dev/toonformat/jtoon/normalizer/JsonNormalizerTest.java

This fix ensures the tests are timezone-agnostic and will pass regardless of the system's timezone configuration.

Reproduction Steps

Run test in UTC+8 environment,error follow

Expected Behavior

no error

Actual Behavior

#My timezone: UTC+8
#e.g. Result of run:JsonNormalizerTest$TemporalTypes.testSQLTimeStamp

Expected:1970-01-21T11:40:19.274 
Actual:1970-01-21T18:40:19.274

org.opentest4j.AssertionFailedError: expected: <1970-01-21T11:40:19.274> but was: <1970-01-21T18:40:19.274>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:158)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:139)
	at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:201)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:184)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:179)
	at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1188)
	at dev.toonformat.jtoon.normalizer.JsonNormalizerTest$TemporalTypes.testSQLTimeStamp(JsonNormalizerTest.java:357)

Environment

timezone: UTC+8
os: macOS 13.15.7
jdk: build 21.0.8+12-LTS-250

Additional Context

No response

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions