diff --git a/CHANGELOG.md b/CHANGELOG.md index d6bda1eb768..4f51a43499f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# ## [Unreleased] ### Changed +- We added a validity check for dates in the `date` and `urldate` fields. - We added a text file export for 'Find Unlinked Files'. [#3341](https://github.com/JabRef/jabref/issues/3341) - We added a fetcher based on RFC-IDs. [#3971](https://github.com/JabRef/jabref/issues/3971) - We changed the implementation of the `[shorttitle]` key pattern. It now removes small words like `a`, `an`, `on`, `the` etc. Refer to the help page for a complete overview. [Feature request in the forum](http://discourse.jabref.org/t/jabref-differences-in-shorttitle-between-versions-3-8-1-and-4-not-discounting-the-a-an-of-in-titles/1147) diff --git a/src/main/java/org/jabref/logic/integrity/DateChecker.java b/src/main/java/org/jabref/logic/integrity/DateChecker.java new file mode 100644 index 00000000000..83f0077b8aa --- /dev/null +++ b/src/main/java/org/jabref/logic/integrity/DateChecker.java @@ -0,0 +1,24 @@ +package org.jabref.logic.integrity; + +import java.util.Optional; + +import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.Date; +import org.jabref.model.strings.StringUtil; + +public class DateChecker implements ValueChecker { + + @Override + public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + + Optional parsedDate = Date.parse(value); + if (!parsedDate.isPresent()) { + return Optional.of(Localization.lang("incorrect format")); + } + + return Optional.empty(); + } +} diff --git a/src/main/java/org/jabref/logic/integrity/FieldCheckers.java b/src/main/java/org/jabref/logic/integrity/FieldCheckers.java index 4358d4729a5..79cca452b11 100644 --- a/src/main/java/org/jabref/logic/integrity/FieldCheckers.java +++ b/src/main/java/org/jabref/logic/integrity/FieldCheckers.java @@ -50,6 +50,13 @@ private static Multimap getAllMap(BibDatabaseContext datab fieldCheckers.put(FieldName.YEAR, new YearChecker()); fieldCheckers.put(FieldName.KEY, new ValidBibtexKeyChecker(enforceLegalKey)); + if (databaseContext.isBiblatexMode()) { + fieldCheckers.put(FieldName.DATE, new DateChecker()); + fieldCheckers.put(FieldName.URLDATE, new DateChecker()); + fieldCheckers.put(FieldName.EVENTDATE, new DateChecker()); + fieldCheckers.put(FieldName.ORIGDATE, new DateChecker()); + } + return fieldCheckers; } diff --git a/src/main/java/org/jabref/model/entry/Date.java b/src/main/java/org/jabref/model/entry/Date.java index fb558155984..b1655ad7c17 100644 --- a/src/main/java/org/jabref/model/entry/Date.java +++ b/src/main/java/org/jabref/model/entry/Date.java @@ -44,9 +44,17 @@ public Date(TemporalAccessor date) { */ public static Optional parse(String dateString) { Objects.requireNonNull(dateString); - List formatStrings = Arrays.asList("uuuu-M-d", "uuuu-M", "d-M-uuuu", "M/uu", "M/uuuu", "MMMM d, uuuu", + List formatStrings = Arrays.asList( + "uuuu-M-d", + "uuuu-M", + "d-M-uuuu", + "M-uuuu", + "M/uu", + "M/uuuu", + "MMMM d, uuuu", "MMMM, uuuu", - "d.M.uuuu", "uuuu.M.d", "uuuu"); + "d.M.uuuu", + "uuuu.M.d", "uuuu"); for (String formatString : formatStrings) { try { diff --git a/src/test/java/org/jabref/logic/integrity/DateCheckerTest.java b/src/test/java/org/jabref/logic/integrity/DateCheckerTest.java new file mode 100644 index 00000000000..21cf8306ef4 --- /dev/null +++ b/src/test/java/org/jabref/logic/integrity/DateCheckerTest.java @@ -0,0 +1,28 @@ +package org.jabref.logic.integrity; + +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class DateCheckerTest { + + private DateChecker checker; + + @BeforeEach + void setUp() { + checker = new DateChecker(); + } + + @Test + void complainsAboutInvalidIsoLikeDate() { + assertEquals(Optional.of("incorrect format"), checker.checkValue("2018-04-21TZ")); + } + + @Test + void acceptsValidIsoDate() { + assertEquals(Optional.empty(), checker.checkValue("2018-04-21")); + } +} diff --git a/src/test/java/org/jabref/model/entry/DateTest.java b/src/test/java/org/jabref/model/entry/DateTest.java index 3234ea84280..3e8ba6127e7 100644 --- a/src/test/java/org/jabref/model/entry/DateTest.java +++ b/src/test/java/org/jabref/model/entry/DateTest.java @@ -1,6 +1,8 @@ package org.jabref.model.entry; import java.time.LocalDate; +import java.time.Year; +import java.time.YearMonth; import java.util.Optional; import org.junit.jupiter.api.Test; @@ -8,15 +10,34 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class DateTest { +class DateTest { @Test - public void parseCorrectlyDayMonthYearDate() throws Exception { + void parseCorrectlyDayMonthYearDate() throws Exception { Date expected = new Date(LocalDate.of(2014, 6, 19)); assertEquals(Optional.of(expected), Date.parse("19-06-2014")); } - public void parseDateNull() { - assertThrows(NullPointerException.class, () -> assertEquals(Optional.empty(), Date.parse(null))); + @Test + void parseCorrectlyMonthYearDate() throws Exception { + Date expected = new Date(YearMonth.of(2014, 6)); + assertEquals(Optional.of(expected), Date.parse("06-2014")); + } + + @Test + void parseCorrectlyYearMonthDate() throws Exception { + Date expected = new Date(YearMonth.of(2014, 6)); + assertEquals(Optional.of(expected), Date.parse("2014-06")); + } + + @Test + void parseCorrectlyYearDate() throws Exception { + Date expected = new Date(Year.of(2014)); + assertEquals(Optional.of(expected), Date.parse("2014")); + } + + @Test + void parseDateNull() { + assertThrows(NullPointerException.class, () -> Date.parse(null)); } }