You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 21中DateFormat::format中英文输出不一致的测试适配问题

Java 21迁移中DateFormat格式字符串比较问题解决

问题背景

将遗留代码从Java 17迁移到Java 21后,发现DateFormat::format方法输出的英文时间字符串(带AM/PM格式)中,空格为非LATIN-1编码字符,导致项目中大量与硬编码预期值的equals断言失败;而德语等非英语语言的输出则无此问题。

复现代码

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import static java.text.DateFormat.SHORT;

public class Main {
    public static void main(String[] args) {
        DateFormat endf = DateFormat.getTimeInstance(SHORT, Locale.ENGLISH);
        endf.setTimeZone(TimeZone.getTimeZone("Europe/London"));

        DateFormat gedf = DateFormat.getTimeInstance(SHORT, Locale.GERMAN);
        gedf.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));

        var enDate = endf.format(new Date(1727163143068L));
        var geDate = gedf.format(new Date(1727163143068L));

        assert(enDate.equals("8:32 AM"));
        assert(geDate.equals("09:32"));

        System.out.println(enDate); // 输出: 8:32 AM 
        System.out.println(geDate); // 输出: 09:32
    }
}

解决方案

1. 标准化空白字符

将格式化后的字符串中的非标准空白字符替换为普通空格,再与预期值比较:

// 替换所有类型的空白字符为普通空格
assert(enDate.replaceAll("\\s", " ").equals("8:32 AM"));

或精准替换常见的非标准空格(如不换行空格U+00A0、窄空格U+202F):

assert(enDate.replaceAll("[\\u00A0\\u202F]", " ").equals("8:32 AM"));

2. 切换到现代日期时间API(推荐)

DateFormat属于旧API,Java 8及以后推荐使用java.time包下的类,其格式化输出更稳定,且从根源避免编码类问题:

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        var dateTime = LocalDateTime.ofEpochSecond(1727163143, 68, java.time.ZoneOffset.UTC);
        
        DateTimeFormatter enFormatter = DateTimeFormatter.ofPattern("h:mm a", Locale.ENGLISH)
                .withZone(ZoneId.of("Europe/London"));
        String enDate = enFormatter.format(dateTime);
        
        DateTimeFormatter deFormatter = DateTimeFormatter.ofPattern("HH:mm", Locale.GERMAN)
                .withZone(ZoneId.of("Europe/Berlin"));
        String geDate = deFormatter.format(dateTime);
        
        assert(enDate.equals("8:32 AM"));
        assert(geDate.equals("09:32"));
    }
}

该API还解决了旧API的线程不安全问题,更适配现代Java开发规范。

3. 语义化比较(最严谨)

跳过字符串格式,将格式化后的字符串重新解析为日期对象,通过时间戳比较语义:

// 解析英文时间字符串回Date对象,比较时间戳
Date parsedEnDate = endf.parse(enDate);
assert(parsedEnDate.getTime() == 1727163143068L);

// 德语时间同理
Date parsedGeDate = gedf.parse(geDate);
assert(parsedGeDate.getTime() == 1727163143068L);

此方法完全不依赖字符串的具体格式,仅校验时间的实际语义,是最可靠的比较方式。


内容的提问来源于stack exchange,提问作者yale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 23:59:56