diff --git a/core/matchers/src/main/kotlin/au/com/dius/pact/core/matchers/MatcherExecutor.kt b/core/matchers/src/main/kotlin/au/com/dius/pact/core/matchers/MatcherExecutor.kt index 20332788c5..c4b748de65 100755 --- a/core/matchers/src/main/kotlin/au/com/dius/pact/core/matchers/MatcherExecutor.kt +++ b/core/matchers/src/main/kotlin/au/com/dius/pact/core/matchers/MatcherExecutor.kt @@ -323,12 +323,21 @@ fun matchDateTime( return if (isCollection(actual)) { emptyList() } else { + var newPattern = pattern try { - DateTimeFormatter.ofPattern(pattern).parse(safeToString(actual)) + /** + Replacing 'Z' with 'X' in order to offer backward compatibility for consumers who might be + using ISO 8601 the UTC designator 'Z' + **/ + if (pattern.endsWith('Z')) { + newPattern = pattern.replace('Z', 'X') + logger.warn { "Found unsupported UTC designator in pattern '$pattern'. Replacing non quote 'Z's with 'X's" } + } + DateTimeFormatter.ofPattern(newPattern).parse(safeToString(actual)) emptyList() } catch (e: DateTimeParseException) { listOf(mismatchFactory.create(expected, actual, - "Expected ${valueOf(actual)} to match a datetime of '$pattern': " + + "Expected ${valueOf(actual)} to match a datetime of '$newPattern': " + "${e.message}", path)) } } diff --git a/core/matchers/src/test/groovy/au/com/dius/pact/core/matchers/MatcherExecutorSpec.groovy b/core/matchers/src/test/groovy/au/com/dius/pact/core/matchers/MatcherExecutorSpec.groovy index d965804482..fa9b0965e0 100755 --- a/core/matchers/src/test/groovy/au/com/dius/pact/core/matchers/MatcherExecutorSpec.groovy +++ b/core/matchers/src/test/groovy/au/com/dius/pact/core/matchers/MatcherExecutorSpec.groovy @@ -149,6 +149,14 @@ class MatcherExecutorSpec extends Specification { '2014-01-01 14:00:00+10:00' | '2013#12#01#14#00#00' | "yyyy'#'MM'#'dd'#'HH'#'mm'#'ss" || true '2014-01-01 14:00:00+10:00' | null | null || false '2014-01-01T10:00+10:00[Australia/Melbourne]' | '2020-01-01T10:00+01:00[Europe/Warsaw]' | "yyyy-MM-dd'T'HH:mmXXX'['zzz']'" || true + '2019-11-25T13:45:00+02:00' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ssX" || true + '2019-11-25T13:45:00+02:00' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ssZZ" || true + '2019-11-25T13:45:00+02:00' | '2019-11-25T11:45Z' | "yyyy-MM-dd'T'HH:mmZZ" || true + '2019-11-25T13:45:00+02:00' | '2019-11-25T11Z' | "yyyy-MM-dd'T'HHZZ" || true + '2019-11-25T13:45:00+0200' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ssZ" || true + '2019-11-25T13:45:00+0200' | '2019-11-25T11:45Z' | "yyyy-MM-dd'T'HH:mmZ" || true + '2019-11-25T13:45:00+0200' | '2019-11-25T11Z' | "yyyy-MM-dd'T'HHZ" || true + '2019-11-25T13:45:00+0200' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ss'Z'" || true matcher = pattern ? new TimestampMatcher(pattern) : new TimestampMatcher() } @@ -159,11 +167,11 @@ class MatcherExecutorSpec extends Specification { MatcherExecutorKt.domatch(matcher, path, expected, actual, mismatchFactory).empty == mustBeEmpty where: - expected | actual | pattern || mustBeEmpty - '14:00:00' | '14:00:00' | null || true - '00:00' | '14:01:02' | 'mm:ss' || false - '00:00:14' | '05:10:14' | 'ss:mm:HH' || true - '14:00:00+10:00' | null | null || false + expected | actual | pattern || mustBeEmpty + '14:00:00' | '14:00:00' | null || true + '00:00' | '14:01:02' | 'mm:ss' || false + '00:00:14' | '05:10:14' | 'ss:mm:HH' || true + '14:00:00+10:00' | null | null || false matcher = pattern ? new TimeMatcher(pattern) : new TimeMatcher() }