Class DateTimeFormats

java.lang.Object
com.google.mu.time.DateTimeFormats

public final class DateTimeFormats extends Object
Utility class with one-stop Instant and ZonedDateTime parsing for all common date time strings, without needing a DateTimeFormatter:

 Instant timestamp = DateTimeFormats.parseToInstant(timestampString);
 ZonedDateTime dateTime = DateTimeFormats.parseZonedDateTime(dateTimeString);
 

For more flexible use cases, where you might want to reuse or conform to a format known at compile-time, the DateTimeFormatter can be inferred from an example date/time/datetime string (similar to the golang time library style).

For example:


 private static final DateTimeFormatter DATE_TIME_FORMATTER =
     DateTimeFormats.formatOf("2023-12-09 10:00:00.12345 America/Los_Angeles");
 private static final DateTimeFormatter USING_ZONE_OFFSET =
     DateTimeFormats.formatOf("2023-12-09 10:00:00+08:00");
 private static final DateTimeFormatter ISO_FORMATTER =
     DateTimeFormats.formatOf("2023-12-09T10:00:00.12345[Europe/Paris]");
 private static final DateTimeFormatter WITH_DAY_OF_WEEK =
     DateTimeFormats.formatOf("2023/12/09 Sat 10:00+08:00");
 

Most ISO 8601 formats are supported, except BASIC_ISO_DATE, ISO_WEEK_DATE ('2012-W48-6') and ISO_ORDINAL_DATE ('2012-337'), which are rarely used.

For the date part of custom patterns, ambiguous examples like 10/12/2024 or 1/2/yyyy are not supported. You should use unambiguous examples like 10/30/2024 (which results in "MM/dd/yyyy"} or 30/1/2024 (which results in "dd/M/yyyy}. In addition, localized month names such as Jan or March are used, all natural orders ( year month day, month day year or day month year) are supported.

For the time part of custom patterns, only HH:mm, HH:mm:ss and HH:mm:ss.S variants are supported (the S can be 1 to 9 digits). An AM/PM marker can follow, as in 1:00 PM or 10:00 PM, in which case a 12-hour clock (h or hh) is inferred and 24-hour values such as 15:00 PM are rejected.

If the variant of the date time pattern you need exceeds the out-of-box support, you can explicitly mix the DateTimeFormatter specifiers with example placeholders (between a pair of pointy brackets) to be translated.

For example the following code uses the dd, MM and yyyy specifiers as is but translates the Tue and America/New_York example snippets into E and VV specifiers respectively. It will then parse and format to datetime strings like "Fri, 20 Oct 2023 10:30:59.123 Europe/Paris".


 private static final DateTimeFormatter FORMATTER =
     formatOf("<Tue>, dd MM yyyy HH:mm:ss.SSS <America/New_York>");
 

Warning: zone abbreviations are lossy across timezones. An abbreviation such as AST, CST or PST is shared by a group of zones. formatOf(java.lang.String) can only translate it to the "zzz" format specifier, preferring ZoneId.systemDefault() when it belongs to that group (which also claims the group's daylight or standard counterpart name, even if the host zone never observes it), and otherwise resolving through CLDR to the group's canonical zone, which may not be the zone that produced the string! Such strings usually come from Date.toString(), which prints an abbreviation whenever CLDR has one for the host's zone. For example, when parsed on a host outside those zones (such as in UTC or America/Los_Angeles):


 // Written by a host in Barbados, which stays on AST (-04:00) year round.
 // The string denotes 2011-07-15T12:00:00Z.
 parseToInstant("Fri Jul 15 08:00:00 AST 2011");
 // => 2011-07-15T11:00:00Z. "AST" resolves to America/Halifax, which is on ADT (-03:00) in July.

 // Written by a host in Shanghai, which also prints CST.
 // The string denotes 2026-09-17T00:00:00Z.
 parseToInstant("Thu Sep 17 08:00:00 CST 2026");
 // => 2026-09-17T13:00:00Z. "CST" resolves to America/Chicago: 13 hours off.
 

The canonical zone of the most common abbreviations:

  • PST, PDT: America/Los_Angeles
  • MST, MDT: America/Denver
  • CST, CDT: America/Chicago
  • EST, EDT: America/New_York
  • AST, ADT: America/Halifax

The drift is an hour where the group differs only in daylight saving (AEST spans Sydney and Brisbane; CET spans Paris and Algiers), and can exceed half a day where the same letters are used on different continents (CST spans Chicago, Havana and Shanghai; PST spans Los Angeles and Manila; AST spans Halifax, Barbados and Riyadh). Nothing in the string identifies the writer's zone, so this is not recoverable when the reader's ZoneId.systemDefault() differs from the writer's.

Prefer a zone id (2011-07-15 08:00:00 America/Barbados) or a numeric offset ( 2011-07-15 08:00:00 -04:00); both round-trip exactly. Use an abbreviation only when the producer is known to run in the same ZoneId.systemDefault(), in the canonical zone, or in a zone that follows the same rules (America/Toronto round-trips through America/New_York). GMT, UTC, UT and GMT±hh:mm are unambiguous and always exact.

i18n isn't supported.

Since:
7.1
  • Method Details

    • formatOf

      public static DateTimeFormatter formatOf(String example)
      Infers and returns the DateTimeFormatter based on example.
      Throws:
      DateTimeException - if example is invalid or the pattern isn't supported.
    • parseLocalDate

      public static LocalDate parseLocalDate(String dateString)
      Parses dateString as LocalDate.

      Acceptable formats include dates like "2024/04/11", "2024-04-11", "2024 April 11", "Apr 11 2024", "11 April 2024", "20240401", or even with "10/30/2024", "30/01/2024" etc. as long as it's not ambiguous.

      Prefer to pre-construct a DateTimeFormatter using formatOf(java.lang.String) to get better performance and earlier error report in case the format cannot be inferred.

      Throws:
      DateTimeException - if dateTimeString cannot be parsed to LocalDate
      Since:
      8.0
    • parseToInstant

      public static Instant parseToInstant(String dateTimeString)
      Parses dateTimeString to Instant. dateTimeString could be in the format of DateTimeFormatter.ISO_INSTANT, which is from Instant.toString(); or it could be any valid date time with zone name or zone offset.

      Prefer to pre-construct a DateTimeFormatter using formatOf(java.lang.String) to get better performance and earlier error report in case the format cannot be inferred.

      If dateTimeString carries a zone abbreviation such as PST or CST, see the class-level warning: when ZoneId.systemDefault() is not in that abbreviation's group, it resolves to CLDR's canonical zone, which may not be the zone that produced the string.

      Parameters:
      dateTimeString - can be the result of Instant.toString(), or any other valid date time with either zone name or UTC offset.
      Throws:
      DateTimeException - if dateTimeString cannot be parsed as Instant
      Since:
      8.0
    • parseZonedDateTime

      public static ZonedDateTime parseZonedDateTime(String dateTimeString)
      Parses dateTimeString to ZonedDateTime using heuristics in this class to infer the DateTimeFormatter for common formats.

      Prefer to pre-construct a DateTimeFormatter using formatOf(java.lang.String) to get better performance and earlier error report in case the format cannot be inferred.

      If dateTimeString carries a zone abbreviation such as PST or CST, see the class-level warning: when ZoneId.systemDefault() is not in that abbreviation's group, it resolves to CLDR's canonical zone, which may not be the zone that produced the string.

      Parameters:
      dateTimeString - must be a string with valid date, time, and zone name or UTC offset
      Throws:
      DateTimeException - if dateTimeString cannot be parsed as ZonedDateTime
      Since:
      8.0
    • parseOffsetDateTime

      public static OffsetDateTime parseOffsetDateTime(String dateTimeString)
      Parses dateTimeString to OffsetDateTime using heuristics in this class to infer the DateTimeFormatter for common formats.

      Prefer to pre-construct a DateTimeFormatter using formatOf(java.lang.String) to get better performance and earlier error report in case the format cannot be inferred.

      Parameters:
      dateTimeString - must be a string with valid date, time, and UTC offset (cannot be zone name)
      Throws:
      DateTimeException - if dateTimeString cannot be parsed as OffsetDateTime
      Since:
      8.0