Format LocalDate to ISO 8601 With T and Z – 用 T 和 Z 将本地日期格式化为 ISO 8601

最后修改: 2023年 12月 25日

中文/混合/英文(键盘快捷键:t)

 1. Overview

1.概述

Handling date and time in a standardized format is crucial when working with applications that deal with different time zones or when exchanging data between systems.

在处理不同时区的应用程序或在系统间交换数据时,以标准化格式处理日期和时间至关重要。

In this tutorial, we’ll explore various techniques for formatting a LocalDate to the ISO 8601 format. This format includes the ‘T‘ separator and the ‘Z‘ indicating UTC time.

在本教程中,我们将探讨将 LocalDate 格式化为 ISO 8601 格式的各种技术。这种格式包括”T“分隔符和表示 UTC 时间的”Z“。

2. LocalDate and ISO 8601

2. 本地日期和 ISO 8601

LocalDate is a part of the modern date and time API introduced in Java 8 under the java.time package. It’s immutable, meaning that once an instance is created, its value cannot be changed. It represents a date without considering the time or time zone, focusing solely on the year, month, and day of the month. LocalDate facilitates convenient manipulation and interaction with date information.

LocalDate 是现代日期和时间 API 的一部分,由 Java 8 中的 java.time 包引入。它是不可变的,这意味着一旦创建了实例,其值就无法更改。它表示日期时不考虑时间或时区,只关注年、月和日。LocalDate方便了对日期信息的操作和交互。

ISO 8601 is an international standard for representing dates and times in a clear, unambiguous, and universally accepted format. It provides a standardized way to express dates and times, which is essential for a wide range of applications. This includes data interchange, international communication, and computer systems.

ISO 8601 是以清晰、明确和普遍接受的格式表示日期和时间的国际标准。它提供了一种表达日期和时间的标准化方法,对于广泛的应用至关重要。这包括数据交换、国际通信和计算机系统。

The ISO 8601 format includes several components, with the most common format being: YYYY-MM-DDThh:mm:ss.sssZ.

ISO 8601 格式包括几个部分,最常见的格式是YYYY-MM-DDThh:mm:ss.sssZ.

Here’s a breakdown of the components:

以下是各组成部分的细目:

  • YYYY: Represents the year with four digits (e.g., 2023)
  • MM: Represents the month with two digits (e.g., 03 for March)
  • DD: Represents the day of the month with two digits (e.g., 15)
  • T‘: A literal ‘T’ character that separates the date from the time
  • hh: Represents the hour of the day in 24-hour format (e.g., 14 for 2 PM)
  • mm: Represents the minutes (e.g., 30)
  • ss: Represents the seconds (e.g., 45)
  • sss: Represents milliseconds (optional and may vary in length)
  • Z‘: A literal ‘Z’ character that indicates the time is in Coordinated Universal Time (UTC)

ISO 8601 allows for various optional components, making it a versatile standard for representing date and time information. For example, we can include time zone offsets or omit seconds and milliseconds when they aren’t relevant.

ISO 8601 允许使用各种可选组件,使其成为表示日期和时间信息的通用标准。例如,我们可以包含时区偏移,或者在不相关时省略秒和毫秒。

The ‘Z’ character indicates that the time is in UTC, but we can also represent time in local time zones by specifying the offset from UTC.

Z“字符表示UTC 时间,但我们也可以通过指定与UTC 的偏移来表示当地时区的时间。

3. Using Java 8 Time API

3.使用 Java 8 时间应用程序接口

Java provides a flexible way to format date and time objects, including LocalDate using the DateTimeFormatter class.

Java 提供了一种灵活的方法来格式化日期和时间对象,包括使用 DateTimeFormatter 类的 LocalDate

Instances of DateTimeFormatter are thread-safe, making them suitable for use in multi-threaded environments without the need for external synchronization.

DateTimeFormatter实例是线程安全的,因此适合在多线程环境中使用,无需外部同步。

Here’s how we can use it to format a LocalDate to ISO 8601:

下面是我们如何使用它将 LocalDate 格式化为 ISO 8601:

class LocalDateToISO {
    String formatUsingDateTimeFormatter(LocalDate localDate) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX");
        String formattedDate = localDate.atStartOfDay().atOffset(ZoneOffset.UTC).format(formatter);
        return formattedDate;
    }

In this example, we create a DateTimeFormatter with a custom pattern that includes ‘T‘ and ‘Z’ in the desired positions. Then, we use the format() method to format the LocalDate into a string with the specified format.

在此示例中,我们创建了一个 DateTimeFormatter 自定义模式,其中包括在所需位置上的”T“和 “Z”。然后,我们使用 format() 方法将 LocalDate 格式化为具有指定格式的字符串。

We can perform a test to verify its expected behavior:

我们可以进行测试,验证其预期行为:

@Test
void givenLocalDate_whenUsingDateTimeFormatter_thenISOFormat(){
    LocalDateToISO localDateToISO = new LocalDateToISO();
    LocalDate localDate = LocalDate.of(2023, 11, 6);

    String expected = "2023-11-06T00:00:00.000Z";
    String actual = localDateToISO.formatUsingDateTimeFormatter(localDate);
    assertEquals(expected, actual);
}

4. Using SimpleDateFormat

4.使用SimpleDateFormat</em

The SimpleDateFormat class is a powerful tool for formatting and parsing dates. It belongs to the java.text package and provides a straightforward way to convert dates between their textual representations and Date objects.

SimpleDateFormat 类是格式化和解析日期的强大工具。它属于java.text包,提供了在文本表示法和日期对象之间转换日期的直接方法

It’s particularly useful for working with legacy date-time types, such as java.util.Date. While it’s not as modern or robust as the java.time API, it can still serve this purpose:

它在处理传统日期时间类型(如 java.util.Date )时尤其有用。虽然它不如 java.time API 那样现代或健壮,但它仍能满足这一目的:

String formatUsingSimpleDateFormat(LocalDate date) {
    Date utilDate = Date.from(date.atStartOfDay(ZoneOffset.UTC).toInstant());
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
    String formattedDate = dateFormat.format(utilDate);
    return formattedDate;
}

In the above example, we’re converting a LocalDate to a ZonedDateTime with ZoneOffset.UTC and then converts it to an Instant object. We can then obtain a Date object from an Instant and perform formatting on the object.

在上面的示例中,我们使用 ZoneOffset.UTCLocalDate 转换为 ZonedDateTime ,然后将其转换为 Instant 对象。然后,我们可以从Instant中获得一个Date对象,并对该对象执行格式化。

Let’s format a LocalDate object using SimpleDateFormat:

让我们使用 SimpleDateFormat 来格式化 LocalDate 对象:

@Test
void givenLocalDate_whenUsingSimpleDateFormat_thenISOFormat(){
    LocalDateToISO localDateToISO = new LocalDateToISO();
    LocalDate localDate = LocalDate.of(2023, 11, 6);

    String expected = "2023-11-06T00:00:00.000Z";
    String actual = localDateToISO.formatUsingSimpleDateFormat(localDate);
    assertEquals(expected, actual);
}

It’s crucial to be aware that SimpleDateFormat isn’t thread-safe. Concurrent usage by multiple threads can lead to unexpected results or exceptions. To address this concern, developers often use ThreadLocal ensuring that each thread possesses its dedicated instance of SimpleDateFormat. This helps in effectively preventing potential thread-safety issues.

需要注意的是,SimpleDateFormat 并非线程安全。多个线程并发使用可能会导致意外结果或异常。为了解决这一问题,开发人员通常使用 ThreadLocal 来确保每个线程都拥有其专用的 SimpleDateFormat 实例。这有助于有效防止潜在的线程安全问题。

5. Using Apache Commons Lang3

5.使用 Apache Commons Lang3

The Apache Commons Lang3 library provides a utility class named FastDateFormat that simplifies date formatting. It’s a fast and thread-safe version of SimpleDateFormat. We can directly substitute this class for SimpleDateFormat in the majority of the formatting and parsing scenarios. It proves particularly beneficial in multi-threaded server environments.

Apache Commons Lang3 库提供了一个名为 FastDateFormat 的实用程序类,可简化日期格式化。它是 SimpleDateFormat 的快速和线程安全版本。在大多数格式化和解析场景中,我们可以直接用该类代替 SimpleDateFormat 。事实证明,它在多线程服务器环境中特别有用。

This approach emphasizes conciseness by utilizing the features of Apache Commons Lang 3 to create Java date formatting code that is clear and straightforward to understand.

这种方法强调简洁,利用 Apache Commons Lang 3 的功能来创建清晰易懂的 Java 日期格式化代码。

We can easily obtain the library from the central Maven repository by including the following dependency:

我们可以通过加入以下依赖关系:从 Maven 中央资源库轻松获取该库

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.14.0</version>
</dependency>

After installing the library, we can employ its methods. Here’s an example illustrating how to use it:

安装该库后,我们就可以使用它的方法了。下面是一个示例,说明如何使用它:

String formatUsingApacheCommonsLang(LocalDate localDate) {
    Date date = Date.from(localDate.atStartOfDay().toInstant(ZoneOffset.UTC));
    String formattedDate = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", TimeZone.getTimeZone("UTC"))
      .format(date);
    return formattedDate;
}

The above code example takes a LocalDate, converts it to a Date, and then formats it into a string with a specific pattern using FastDateFormat to format the LocalDate to ISO 8601.

上述代码示例获取 LocalDate 并将其转换为 Date ,然后使用 FastDateFormat 将其格式化为具有特定模式的字符串,从而将 LocalDate 格式化为 ISO 8601。

Let’s move on to testing this example:

让我们继续测试这个示例:

@Test
void givenLocalDate_whenUsingApacheCommonsLang_thenISOFormat() {
    LocalDateToISO localDateToISO = new LocalDateToISO();
    LocalDate localDate = LocalDate.of(2023, 11, 6);

    String expected = "2023-11-06T00:00:00.000Z";
    String actual = localDateToISO.formatUsingApacheCommonsLang(localDate);
    assertEquals(expected, actual);
}

6. Using Joda-Time

6.使用 Joda-Time

Joda-Time is a widely-used Java library designed to address the shortcomings of the original date and time classes in java.util package. Before the advent of the java.time API in Java 8, Joda-Time served as a popular and powerful alternative for handling date and time operations.

Joda-Time是一个广泛使用的 Java 库,旨在解决 java.util 包中原始日期和时间类的不足之处。在 Java 8 中的 java.time API 出现之前,Joda-Time 是处理日期和时间操作的一个流行且功能强大的替代方案。

To incorporate the features of the Joda-Time library, we should include the following dependency to our pom.xml:

要整合 Joda-Time 库的功能,我们应在 pom.xml 中包含以下 依赖关系

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.12.5</version>
</dependency>

While it’s no longer necessary in Java 8 and later, it remains an option for pre-existing codebases:

虽然在 Java 8 及更高版本中已不再需要它,但对于已有的代码库来说,它仍然是一个选项:

String formatUsingJodaTime(org.joda.time.LocalDate localDate) {
    org.joda.time.format.DateTimeFormatter formatter = ISODateTimeFormat.dateTime();
    return formatter.print(localDate.toDateTimeAtStartOfDay(DateTimeZone.UTC));
}

In the above example, the DateTimeFormatter from Joda-Time is used to format the LocalDate to ISO 8601.

在上例中,Joda-Time 中的 DateTimeFormatter 用于将 LocalDate 格式化为 ISO 8601。

Let’s test it out:

让我们来测试一下:

@Test
void givenLocalDate_whenUsingJodaTime_thenISOFormat() {
    LocalDateToISO localDateToISO = new LocalDateToISO();
    org.joda.time.LocalDate localDate = new org.joda.time.LocalDate(2023, 11, 6);

    String expected = "2023-11-06T00:00:00.000Z";
    String actual = localDateToISO.formatUsingJodaTime(localDate);
    assertEquals(expected, actual);
}

7. Conclusion

7.结论

In this article, we talked about the different ways of formatting a LocalDate to ISO 8601 with ‘T‘ and ‘Z‘ in Java. The choice of method depends on our preference for code readability and maintainability.

在本文中,我们讨论了在 Java 中使用”T“和”Z“将 LocalDate 格式化为 ISO 8601 的不同方法。选择哪种方法取决于我们对代码可读性和可维护性的偏好。

We can choose the method that best suits our needs, and ensure that our date and time representations adhere to the ISO 8601 standard for consistency and interoperability. The DateTimeFormatter approach is more flexible and suitable for handling various formatting requirements, while the other methods provide simpler solutions for specific scenarios.

我们可以选择最适合我们需要的方法,并确保我们的日期和时间表示符合 ISO 8601 标准,以实现一致性和互操作性。DateTimeFormatter 方法更加灵活,适合处理各种格式化要求,而其他方法则为特定场景提供了更简单的解决方案。

As always, the full source code is available over on GitHub.

一如既往,您可以在 GitHub 上获取完整的源代码