在 Java 中获取包含允许的文件名字符的完整区域设置日期和小时字符串的好方法是什么?

Ric*_*nes 0 java time filenames date

我想构建一个带有区域设置日期和小时的字符串,连接起来,它必须是人类可读的并且与最常见的操作系统文件允许的字符兼容。就像是:

6-23-20_03-06-50

我将此用作用户的自动文件名建议。为此,我编写了以下代码:

public class CustomDateProvider {

    private static final String TWO_DIGIT_PATTERN = "%02d";

    public static String getDashedDateAndHourFromDate(Date date) {
        ZonedDateTime dateTime = date.toInstant().atZone(ZoneId.systemDefault());
        int hour = dateTime.getHour();
        int minute = dateTime.getMinute();
        int second = dateTime.getSecond();

        DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
        String localeDate = dateFormat.format(date);
        String dashedDate = localeDate.replace("/", "-");

        return dashedDate
                + "_"
                + String.format(TWO_DIGIT_PATTERN, hour)
                + "-"
                + String.format(TWO_DIGIT_PATTERN, minute)
                + "-"
                + String.format(TWO_DIGIT_PATTERN, second);
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,我假设日期分隔符字符将始终为“ / ”,并且我不确定这是否总是正确的。无论哪种方式,可能都有更好的方法来实现我的目标,我会很感激任何改进。

Bas*_*que 5

时间

您正在使用多年前被现代java.time类取代的糟糕的日期时间类。

避免本地化格式

您要求以各种本地化格式表示日期时间值的文本。这种方法在文件名中是不明智的。

  • 本地化格式很可能包含在各种文件系统上会出现问题的字符。您MM/dd/yyyy使用斜杠字符的示例格式可能会导致某些面向Unix/ POSIX的文件系统出现问题。
  • 假设不同习惯的人可能会误解本地化格式。
  • 本地化格式可能会使将该字符串解析回日期时间值变得困难或不可能。

相反,我强烈建议仅使用标准ISO 8601格式。

ISO 8601 的“基本”变体

您要求:

必须是人类可读和兼容的

我建议坚持使用最少使用分隔符的ISO 8601格式的“基本”变体。为了与各种文件系统兼容,您希望避免使用斜杠、反斜杠、冒号和空格字符。

ISO 8601 格式按重要性顺序排列:年、月、日、小时、分钟、秒、小数秒。大写字母T将日期部分与时间部分分开。此类字符串按时间顺序按字母顺序排序。

世界标准时间

我还建议您坚持使用UTC(零时分秒的偏移量)。为此,请使用Instant(或OffsetDateTime设置为 UTC)。

Instant instant = Instant.now() ; // Capture current moment as seen in UTC.
Run Code Online (Sandbox Code Playgroud)

如果您不想要小数秒或分钟,请截断。

Instant instant = Instant.now().truncatedTo( ChronoUnit.MINUTES ) ;
Run Code Online (Sandbox Code Playgroud)

您将执行字符串操作以删除年-月-日之间的连字符和时-分-秒之间的冒号。

String output = instant.replace( "-" , "" ).replace( ":" , "" ) ;
Run Code Online (Sandbox Code Playgroud)

对于 2021-01-23T12:30:35Z,这将是:

20210123T123035Z

尾随Z表示UTC,发音为“Zulu”。

分区时刻

如果您坚持使用在特定时区中看到的日期时间,请使用ZonedDateTime.

ZoneId z = ZoneId.systemDefault() ;  // Or ZoneId.of( "Africa/Tunis" ) and such.
ZonedDateTime zdt = ZonedDateTime.now().truncatedTo( ChronoUnit.MINUTES ) ;
Run Code Online (Sandbox Code Playgroud)

指定格式模式。

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmss" ) ;
String output = zdt.format( f ) ;
Run Code Online (Sandbox Code Playgroud)

例子:

20210123T123035

我不建议省略 zone 或 offset,但如果你坚持,你就可以了。

如果您坚持使用 的示例格式6-23-20_03-06-50,请定义一个DateTimeFormatter以匹配。

DateTimeFormatter f = DateTimeFormatter.ofPattern( "M-d-uu'_'HH-mm-ss" ) ;
Run Code Online (Sandbox Code Playgroud)

允许单位数的月份或日期是我建议反对的另一件事。两位数年份的使用也是如此。


Java 中所有日期时间类型的表,包括现代的和传统的


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

现在处于维护模式Joda-Time项目建议迁移到java.time类。

您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。Hibernate 5 & JPA 2.2 支持java.timejava.sql.*

从哪里获得 java.time 类?