Skip to content

Commit

Permalink
parseToLocalDate()
Browse files Browse the repository at this point in the history
  • Loading branch information
fluentfuture committed Apr 12, 2024
1 parent 27f0b92 commit fadb5df
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 2 deletions.
25 changes: 23 additions & 2 deletions mug/src/main/java/com/google/mu/time/DateTimeFormats.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
Expand Down Expand Up @@ -128,7 +129,8 @@ public final class DateTimeFormats {
BiStream.of(
forExample("2011-12-03"), DateTimeFormatter.ISO_LOCAL_DATE,
forExample("2011-12-03+08:00"), DateTimeFormatter.ISO_DATE,
forExample("2011-12-03-08:00"), DateTimeFormatter.ISO_DATE).toMap();
forExample("2011-12-03-08:00"), DateTimeFormatter.ISO_DATE,
forExample("20111203"), DateTimeFormatter.BASIC_ISO_DATE).toMap();

/** These ISO formats all support optional nanoseconds in the format of ".nnnnnnnnn". */
private static final Map<List<?>, DateTimeFormatter> ISO_DATE_TIME_FORMATTERS =
Expand Down Expand Up @@ -278,11 +280,30 @@ public static DateTimeFormatter formatOf(String example) {
private static <T> T parseDateTime(String dateTimeString, TemporalQuery<T> query) {
List<?> signature = forExample(dateTimeString);
return lookup(RFC_1123_FORMATTERS, signature)
.orElseGet(() -> lookup(ISO_DATE_FORMATTERS, signature)
.orElseGet(() -> lookup(ISO_DATE_TIME_FORMATTERS, forExample(removeNanosecondsPart(dateTimeString)))
.orElseGet(() -> DateTimeFormatter.ofPattern(inferDateTimePattern(dateTimeString, signature))))
.orElseGet(() -> DateTimeFormatter.ofPattern(inferDateTimePattern(dateTimeString, signature)))))
.parse(dateTimeString, query);
}

/**
* Parses {@code dateString} to {@link LocalDate}. {@code dateString} could be in the format
* of {@link DateTimeFormatter#ISO_DATE}, {@link DateTimeFormatter#BASIC_ISO_DATE}
* or dates with natural month names like "Jan" or "January".
*
* <p>If {@code dateString} has valid time and timezone, they'll be ignored.
*
* <p>Prefer to pre-construct a {@link DateTimeFormatter} using {@link #formatOf} to get
* better performance and earlier error report in case the example date time string cannot
* be inferred.
*
* @throws DateTimeException if {@code dateTimeString} cannot be parsed to {@link LocalDate}
* @since 8.0
*/
public static LocalDate parseToLocalDate(String dateString) {
return parseDateTime(dateString, LocalDate::from);
}

/**
* Parses {@code dateTimeString} to {@link Instant}. {@code dateTimeString} could be in the format
* of {@link DateTimeFormatter#ISO_INSTANT}, which is from {@link Instant#toString};
Expand Down
84 changes: 84 additions & 0 deletions mug/src/test/java/com/google/mu/time/DateTimeFormatsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,8 @@ public void parseOffsetDateTime_nonStandardFormat()
public void parseOffsetDateTime_invalid()
throws Exception {
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseOffsetDateTime("2020-01-01T00:00:00.123 bad +08:00"));
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseOffsetDateTime("2020-01-01"));
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseOffsetDateTime("2020/01/01"));
}

@Test
Expand All @@ -693,6 +695,8 @@ public void parseZonedDateTime_nonStandardFormat()
public void parseZonedDateTime_invalid()
throws Exception {
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseZonedDateTime("2020-01-01T00:00:00.123 bad +08:00"));
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseZonedDateTime("2020-01-01"));
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseZonedDateTime("2020/01/02"));
}

@Test
Expand Down Expand Up @@ -723,6 +727,86 @@ public void parseToInstant_nonStandardFormat()
public void parseToInstant_invalid()
throws Exception {
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseToInstant("2020-01-01T00:00:00.123 bad +08:00"));
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseToInstant("2020-01-01"));
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseToInstant("2020/01/01"));
}

@Test
public void parseLocalDate_basicIsoDate() {
assertThat(DateTimeFormats.parseToLocalDate("20211020")).isEqualTo(LocalDate.of(2021, 10, 20));
assertThat(DateTimeFormats.parseToLocalDate("20211001")).isEqualTo(LocalDate.of(2021, 10, 1));
assertThat(DateTimeFormats.parseToLocalDate("20210101")).isEqualTo(LocalDate.of(2021, 1, 1));
}

@Test
public void parseLocalDate_isoDate() {
assertThat(DateTimeFormats.parseToLocalDate("2021-10-20")).isEqualTo(LocalDate.of(2021, 10, 20));
assertThat(DateTimeFormats.parseToLocalDate("2021-10-01")).isEqualTo(LocalDate.of(2021, 10, 1));
assertThat(DateTimeFormats.parseToLocalDate("2021-01-01")).isEqualTo(LocalDate.of(2021, 1, 1));
assertThat(DateTimeFormats.parseToLocalDate("2021-01-2")).isEqualTo(LocalDate.of(2021, 1, 2));
}

@Test
public void parseLocalDate_euDate_mmddyyyy() {
assertThat(DateTimeFormats.parseToLocalDate("10-30-2021")).isEqualTo(LocalDate.of(2021, 10, 30));
assertThat(DateTimeFormats.parseToLocalDate("1-30-2021")).isEqualTo(LocalDate.of(2021, 1, 30));
assertThat(DateTimeFormats.parseToLocalDate("10/20/2021")).isEqualTo(LocalDate.of(2021, 10, 20));
assertThat(DateTimeFormats.parseToLocalDate("1/20/2021")).isEqualTo(LocalDate.of(2021, 1, 20));
}

@Test
public void parseLocalDate_euDate_ddmmyyyy() {
assertThat(DateTimeFormats.parseToLocalDate("30-10-2021")).isEqualTo(LocalDate.of(2021, 10, 30));
assertThat(DateTimeFormats.parseToLocalDate("20/10/2021")).isEqualTo(LocalDate.of(2021, 10, 20));
}

@Test
public void parseLocalDate_withMonthName_yyyymmdd() {
assertThat(DateTimeFormats.parseToLocalDate("2021 Oct 20")).isEqualTo(LocalDate.of(2021, 10, 20));
assertThat(DateTimeFormats.parseToLocalDate("2021 October 1")).isEqualTo(LocalDate.of(2021, 10, 1));
}

@Test
public void parseLocalDate_withMonthName_mmddyyyy() {
assertThat(DateTimeFormats.parseToLocalDate("Oct 20 2021")).isEqualTo(LocalDate.of(2021, 10, 20));
assertThat(DateTimeFormats.parseToLocalDate("October 1 2021")).isEqualTo(LocalDate.of(2021, 10, 1));
}

@Test
public void parseLocalDate_isoDateWithSlash() {
assertThat(DateTimeFormats.parseToLocalDate("2021/10/20")).isEqualTo(LocalDate.of(2021, 10, 20));
assertThat(DateTimeFormats.parseToLocalDate("2021/10/01")).isEqualTo(LocalDate.of(2021, 10, 1));
assertThat(DateTimeFormats.parseToLocalDate("2021/01/01")).isEqualTo(LocalDate.of(2021, 1, 1));
assertThat(DateTimeFormats.parseToLocalDate("2021/01/2")).isEqualTo(LocalDate.of(2021, 1, 2));
}

@Test
public void parseLocalDate_instantHasNoDate() {
Instant time = OffsetDateTime.of(2024, 4, 1, 10, 05, 30, 0, ZoneOffset.UTC).toInstant();
assertThrows(
DateTimeException.class,
() -> DateTimeFormats.parseToLocalDate(time.toString()));
}

@Test
public void parseLocalDate_fromZonedDateTimeString() {
ZonedDateTime time = ZonedDateTime.of(2024, 4, 1, 10, 05, 30, 0, ZoneId.of("America/New_York"));
assertThat(DateTimeFormats.parseToLocalDate(time.toString())).isEqualTo(LocalDate.of(2024, 4, 1));
}

@Test
public void parseLocalDate_fromOffsetDateTimeString() {
OffsetDateTime time = OffsetDateTime.of(2024, 4, 1, 10, 05, 30, 0, ZoneOffset.of("-08:30"));
assertThat(DateTimeFormats.parseToLocalDate(time.toString())).isEqualTo(LocalDate.of(2024, 4, 1));
}

@Test
public void parseLocalDate_incorrectDate() {
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseToLocalDate("20213001"));
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseToLocalDate("2021/30/01"));
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseToLocalDate("2021-30-01"));
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseToLocalDate("01-01-2021"));
assertThrows(DateTimeException.class, () -> DateTimeFormats.parseToLocalDate("01/01/2021"));
}

@Test
Expand Down

0 comments on commit fadb5df

Please sign in to comment.