SimpleDateFormat - 格式 - 九月 - JDK16

问题描述

我刚刚将 Java 从 JDK-15 升级到 JDK-16,但在使用 Date 转换 SimpleDateFormat 时发现问题。仅使用 yyyy-MMM-dd 格式化的 9 月就给出了 4 个字符而不是 3 个字符。

例如:2021-Sep-11 显示2021-Sept-11

    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.DATE,150);
    SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MMM-dd");
    System.out.println(cal.getTime());

    String formatted = format1.format(cal.getTime());
    System.out.println(formatted);

对我来说看起来像是一个错误。我在发行说明中看不到对此的任何更新。有人面临类似的问题吗?一直工作到 JDK-15。

解决方法

不要使用没有 Locale 的日期时间格式/解析类型,因为文本是 Locale 敏感的。

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE,150);
        SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MMM-dd",Locale.ENGLISH);
        System.out.println(cal.getTime());

        String formatted = format1.format(cal.getTime());
        System.out.println(formatted);
    }
}

输出:

2021-Sep-11

请注意,java.util 日期时间 API 及其格式 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到 java.timemodern date-time API*

使用现代日期时间 API:

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

public class Main {
    public static void main(String[] args) {
        // Change ZoneId as per your requirement e.g. ZoneId.of("Europe/London")
        LocalDate date = LocalDate.now(ZoneId.systemDefault());
        date = date.plusDays(150);
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MMM-dd",Locale.ENGLISH);
        String formatted = dtf.format(date);
        System.out.println(formatted);
    }
}

输出:

2021-Sep-11

查看 this answer 以了解有关 uy 的更多信息。

Trail: Date Time 了解有关现代日期时间 API 的更多信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

,

这是一个将在 9 月保留的版本:

final Calendar cal = Calendar.getInstance();
/**/           cal.set(2021,Calendar.SEPTEMBER,11,23,59,59);

final String           pattern = "yyyy-MMM-dd LL LLL EEE EEEE";
final SimpleDateFormat format1 = new SimpleDateFormat(pattern);

System.out.println("Locale..: " + Locale.getDefault());
System.out.println("Calendar: " + cal.getTime());
System.out.println("Pattern.: " + pattern + " -> " + format1.format(cal.getTime()));

System.out.println("Vendor..: " + ManagementFactory.getRuntimeMXBean().getVmVendor());
System.out.println("VM......: " + ManagementFactory.getRuntimeMXBean().getVmName());
System.out.println("Version.: " + ManagementFactory.getRuntimeMXBean().getSpecVersion());
System.out.println("Build...: " + ManagementFactory.getRuntimeMXBean().getVmVersion());

在德语系统上,它为我生成以下输出:

Locale..: de_DE
Calendar: Sat Sep 11 23:59:59 CEST 2021
Pattern.: yyyy-MMM-dd LL LLL EEE EEEE -> 2021-Sept.-11 09 Sep Sa. Samstag
Vendor..: Oracle Corporation
VM......: Java HotSpot(TM) 64-Bit Server VM
Version.: 16
Build...: 16+36-2231

Locale..: de_DE
Calendar: Sat Sep 11 23:59:59 CEST 2021
Pattern.: yyyy-MMM-dd LL LLL EEE EEEE -> 2021-Sep-11 09 Sep Sa Samstag
Vendor..: Oracle Corporation
VM......: Java HotSpot(TM) 64-Bit Server VM
Version.: 1.8
Build...: 25.40-b25

在这里,SimpleDateFormat 也为 Month 生成了不同的格式,但 Spec.有点模糊。它说:

“月份:如果模式字母的数量为 3 个或更多,则将月份解释为文本”

到目前为止一切都很好,但它限定“文本”如下...

“文本:对于格式,如果模式字母的数量为 4 个或更多,则使用完整形式;否则,如果可用,则使用简短或缩写形式。”

但是对于我们的示例,有 3 个模式字母,这个简短的形式是什么还不清楚。

但也许“L”会对月份名称有所帮助?