diff --git a/google-cloud-clients/google-cloud-core/src/main/java/com/google/cloud/Date.java b/google-cloud-clients/google-cloud-core/src/main/java/com/google/cloud/Date.java index 442e7dca0eef..d7f3b71275e7 100644 --- a/google-cloud-clients/google-cloud-core/src/main/java/com/google/cloud/Date.java +++ b/google-cloud-clients/google-cloud-core/src/main/java/com/google/cloud/Date.java @@ -21,15 +21,12 @@ import java.io.Serializable; import java.util.Calendar; import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** Represents a Date without time, such as 2017-03-17. Date is timezone independent. */ @BetaApi("This is going to be replaced with LocalDate from threetenbp") public final class Date implements Comparable, Serializable { // Date format "yyyy-mm-dd" - private static final Pattern FORMAT_REGEXP = Pattern.compile("(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)"); private static final long serialVersionUID = 8067099123096783929L; private final int year; private final int month; @@ -57,14 +54,19 @@ public static Date fromYearMonthDay(int year, int month, int dayOfMonth) { /** @param date Data in RFC 3339 date format (yyyy-mm-dd). */ public static Date parseDate(String date) { - Matcher matcher = FORMAT_REGEXP.matcher(date); - if (!matcher.matches()) { - throw new IllegalArgumentException("Invalid date: " + date); + Preconditions.checkNotNull(date); + final String invalidDate = "Invalid date: " + date; + Preconditions.checkArgument(date.length() == 10, invalidDate); + Preconditions.checkArgument(date.charAt(4) == '-', invalidDate); + Preconditions.checkArgument(date.charAt(7) == '-', invalidDate); + try { + int year = Integer.parseInt(date.substring(0, 4)); + int month = Integer.parseInt(date.substring(5, 7)); + int dayOfMonth = Integer.parseInt(date.substring(8, 10)); + return new Date(year, month, dayOfMonth); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(invalidDate, e); } - int year = Integer.parseInt(matcher.group(1)); - int month = Integer.parseInt(matcher.group(2)); - int dayOfMonth = Integer.parseInt(matcher.group(3)); - return new Date(year, month, dayOfMonth); } /** diff --git a/google-cloud-clients/google-cloud-core/src/test/java/com/google/cloud/DateTest.java b/google-cloud-clients/google-cloud-core/src/test/java/com/google/cloud/DateTest.java index 5892cc718b01..14b6a139d004 100644 --- a/google-cloud-clients/google-cloud-core/src/test/java/com/google/cloud/DateTest.java +++ b/google-cloud-clients/google-cloud-core/src/test/java/com/google/cloud/DateTest.java @@ -18,6 +18,7 @@ import static com.google.common.testing.SerializableTester.reserializeAndAssert; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; import com.google.common.testing.EqualsTester; import java.text.ParseException; @@ -34,10 +35,80 @@ public class DateTest { @Test public void parseDate() { - Date date = Date.parseDate("2016-09-18"); - assertThat(date.getYear()).isEqualTo(2016); - assertThat(date.getMonth()).isEqualTo(9); - assertThat(date.getDayOfMonth()).isEqualTo(18); + verifyDate("2016-09-18", 2016, 9, 18); + verifyDate("2000-01-01", 2000, 1, 1); + verifyDate("9999-12-31", 9999, 12, 31); + verifyDate("0001-01-01", 1, 1, 1); + verifyDate("2000-02-29", 2000, 2, 29); // This is a valid leap year. + verifyDate("1900-02-29", 1900, 2, 29); // This is NOT a valid leap year. + verifyDate("2001-02-29", 2001, 2, 29); // Also not a valid leap year. + verifyDate("2000-04-31", 2000, 4, 31); // Not a valid date. + } + + private void verifyDate(String input, int year, int month, int day) { + Date date = Date.parseDate(input); + assertThat(date.getYear()).isEqualTo(year); + assertThat(date.getMonth()).isEqualTo(month); + assertThat(date.getDayOfMonth()).isEqualTo(day); + } + + @Test + public void parseInvalidDates() { + parseInvalidDate("2016/09/18"); + parseInvalidDate("2016 09 18"); + parseInvalidDate("2016-9-18"); + parseInvalidDate("2016-09-18T10:00"); + parseInvalidDate(""); + parseInvalidDate("test"); + parseInvalidDate("aaaa-bb-cc"); + parseInvalidDate("aaaa-01-01"); + parseInvalidDate("2019-bb-01"); + parseInvalidDate("2019-01-cc"); + parseInvalidMonth("2000-13-01"); + parseInvalidMonth("2000-00-01"); + parseInvalidDay("2000-12-32"); + parseInvalidDay("2000-12-00"); + parseInvalidDate("10000-01-01"); + parseInvalidYear("0000-01-01"); + parseInvalidYear("-001-01-01"); + parseInvalidMonth("0001--1-01"); + parseInvalidDay("0001-01--1"); + } + + private void parseInvalidDate(String input) { + try { + Date.parseDate(input); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains("Invalid date"); + } + } + + private void parseInvalidYear(String input) { + try { + Date.parseDate(input); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains("Invalid year"); + } + } + + private void parseInvalidMonth(String input) { + try { + Date.parseDate(input); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains("Invalid month"); + } + } + + private void parseInvalidDay(String input) { + try { + Date.parseDate(input); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains("Invalid day"); + } } @Test