ZetCode

Java ResolverStyle 枚举

最后修改时间:2025 年 4 月 16 日

java.time.format.ResolverStyle 枚举控制日期和时间解析如何处理冲突和歧义。它是 Java 8 日期和时间 API 的一部分。该枚举定义了三种风格:STRICT(严格)、SMART(智能)和 LENIENT(宽松)。

ResolverStyle 决定了日期时间解析如何将字段解析为值。它会影响解析期间的验证。风格的选择会影响是否拒绝或调整无效日期。这对于健壮的日期时间处理至关重要。

ResolverStyle 枚举概述

ResolverStyle 枚举提供了三种解析策略。STRICT 严格遵循精确的日历规则。SMART 进行合理的调整。LENIENT 允许任何值,并处理溢出。每种风格都服务于应用程序中的不同用例。

public enum ResolverStyle {
    STRICT,
    SMART,
    LENIENT
}

代码显示了简单的枚举定义。尽管它很简单,但它对解析行为有重大影响。该风格通常在解析操作之前在 DateTimeFormatter 上设置。

STRICT ResolverStyle

STRICT 模式根据其有效范围严格验证所有字段。它拒绝这些范围之外的任何值。当输入必须完全根据日历规则正确时,这很有用。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;

public class Main {

    public static void main(String[] args) {
        
        DateTimeFormatter strictFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd")
            .withResolverStyle(ResolverStyle.STRICT);
        
        // Valid date
        LocalDate validDate = LocalDate.parse("2023-02-28", strictFormatter);
        System.out.println("Valid date: " + validDate);
        
        try {
            // Invalid date (February 30 doesn't exist)
            LocalDate invalidDate = LocalDate.parse("2023-02-30", strictFormatter);
            System.out.println("This won't be printed");
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

此示例显示 STRICT 模式拒绝无效日期。2 月 30 日不存在,因此解析失败。对于其他 Resolver 风格,可能会接受相同的输入。STRICT 是验证场景的理想选择。

SMART ResolverStyle

SMART 模式对无效值进行合理的调整。在大多数情况下,它是默认样式。例如,2 月 30 日变为 2 月 28 日(或闰年的 2 月 29 日)。这平衡了验证与可用性。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;

public class Main {

    public static void main(String[] args) {
        
        DateTimeFormatter smartFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd")
            .withResolverStyle(ResolverStyle.SMART);
        
        // Adjusts February 30 to February 28 (2023 not a leap year)
        LocalDate adjustedDate = LocalDate.parse("2023-02-30", smartFormatter);
        System.out.println("Adjusted date: " + adjustedDate);
        
        // Leap year example (adjusts to February 29)
        LocalDate leapYearDate = LocalDate.parse("2024-02-30", smartFormatter);
        System.out.println("Leap year adjusted date: " + leapYearDate);
    }
}

此示例演示了 SMART 模式的智能调整。无效日期被映射到最近的有效日期。调整考虑了闰年和月份长度。SMART 为大多数应用程序提供了良好的平衡。

LENIENT ResolverStyle

LENIENT 模式允许任何值,并通过滚动到后续单元来处理溢出。这可以在未来或过去创建遥远的日期。它对于某些计算很有用,但对于验证来说很危险。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;

public class Main {

    public static void main(String[] args) {
        
        DateTimeFormatter lenientFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd")
            .withResolverStyle(ResolverStyle.LENIENT);
        
        // Rolls over extra days to next months
        LocalDate rolledDate = LocalDate.parse("2023-02-45", lenientFormatter);
        System.out.println("Lenient date: " + rolledDate); // 2023-03-17
        
        // Negative values roll backwards
        LocalDate negativeDate = LocalDate.parse("2023-02--10", lenientFormatter);
        System.out.println("Negative days: " + negativeDate); // 2023-01-21
    }
}

此示例显示了 LENIENT 模式的溢出处理。超出月份长度的天数将滚动到后续月份。负值向后滚动。这对于计算功能强大,但不适用于输入验证。

比较 ResolverStyles

不同的 Resolver 风格对相同的输入产生不同的结果。此示例并排演示了所有三种风格。比较突出了它们在有问题的输入下的不同行为。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;

public class Main {

    public static void main(String[] args) {
        
        String input = "2023-04-31"; // April has only 30 days
        
        DateTimeFormatter strict = DateTimeFormatter.ofPattern("uuuu-MM-dd")
            .withResolverStyle(ResolverStyle.STRICT);
        
        DateTimeFormatter smart = DateTimeFormatter.ofPattern("uuuu-MM-dd")
            .withResolverStyle(ResolverStyle.SMART);
        
        DateTimeFormatter lenient = DateTimeFormatter.ofPattern("uuuu-MM-dd")
            .withResolverStyle(ResolverStyle.LENIENT);
        
        try {
            System.out.println("STRICT: " + LocalDate.parse(input, strict));
        } catch (Exception e) {
            System.out.println("STRICT failed: " + e.getMessage());
        }
        
        System.out.println("SMART: " + LocalDate.parse(input, smart));
        System.out.println("LENIENT: " + LocalDate.parse(input, lenient));
    }
}

此示例清楚地显示了三种行为。STRICT 拒绝无效输入。SMART 调整到最后一个有效日期。LENIENT 滚动到下个月。理解这些差异有助于为每个用例选择正确的风格。

ResolverStyle 与 DateTimeFormatterBuilder

在构建自定义格式化程序时可以设置 ResolverStyle。此示例展示了与 DateTimeFormatterBuilder 的集成。即使在复杂的格式化程序配置中,该风格也会影响解析行为。

Main.java
package com.zetcode;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.ResolverStyle;
import java.time.format.SignStyle;
import java.time.temporal.ChronoField;

public class Main {

    public static void main(String[] args) {
        
        DateTimeFormatter customFormatter = new DateTimeFormatterBuilder()
            .appendValue(ChronoField.YEAR, 4, 4, SignStyle.EXCEEDS_PAD)
            .appendLiteral('-')
            .appendValue(ChronoField.MONTH_OF_YEAR, 2)
            .appendLiteral('-')
            .appendValue(ChronoField.DAY_OF_MONTH, 2)
            .appendLiteral(' ')
            .appendValue(ChronoField.HOUR_OF_DAY, 2)
            .appendLiteral(':')
            .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
            .toFormatter()
            .withResolverStyle(ResolverStyle.STRICT);
        
        try {
            LocalDateTime dt = LocalDateTime.parse("2023-02-30 12:30", customFormatter);
            System.out.println("Parsed: " + dt);
        } catch (Exception e) {
            System.out.println("Failed with STRICT: " + e.getMessage());
        }
    }
}

此示例使用 STRICT 解析构建了一个自定义格式化程序。无效日期 2 月 30 日被拒绝。相同的构建器可以使用 SMART 或 LENIENT 风格。该风格会影响格式化程序的所有解析操作。

ResolverStyle 与 Year-Month 模式

ResolverStyle 对年份月份解析的影响与完整日期不同。此示例显示了年份月份模式下的行为。该风格会影响如何处理无效的月份值。

Main.java
package com.zetcode;

import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;

public class Main {

    public static void main(String[] args) {
        
        DateTimeFormatter strict = DateTimeFormatter.ofPattern("uuuu-MM")
            .withResolverStyle(ResolverStyle.STRICT);
        
        DateTimeFormatter smart = DateTimeFormatter.ofPattern("uuuu-MM")
            .withResolverStyle(ResolverStyle.SMART);
        
        String input = "2023-13"; // Invalid month 13
        
        try {
            YearMonth.parse(input, strict);
        } catch (Exception e) {
            System.out.println("STRICT rejects month 13: " + e.getMessage());
        }
        
        try {
            YearMonth.parse(input, smart);
        } catch (Exception e) {
            System.out.println("SMART also rejects month 13: " + e.getMessage());
        }
        
        // LENIENT allows month overflow
        DateTimeFormatter lenient = DateTimeFormatter.ofPattern("uuuu-MM")
            .withResolverStyle(ResolverStyle.LENIENT);
        YearMonth lenientYm = YearMonth.parse("2023-13", lenient);
        System.out.println("LENIENT rolls over: " + lenientYm); // 2024-01
    }
}

此示例表明 SMART 和 STRICT 都会拒绝月份 13。只有 LENIENT 允许它通过滚动到下一年。此行为与完整日期中的日期处理不同。了解这些细微差别可以避免意外情况。

来源

Java ResolverStyle 枚举文档

在本文中,我们彻底探讨了 ResolverStyle 枚举及其对日期时间解析的影响。理解这些风格有助于在 Java 应用程序中构建健壮的日期时间处理。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员,在该领域拥有多年的经验。我从 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和 8 本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助其他人掌握编程概念。

列出所有Java教程