SimpleDateFormat mm:ss 格式 - 分钟用 3 填充

SimpleDateFormat mm:ss format - minutes get padded with a 3

我遇到了最奇怪的问题 - 在我们的应用程序中,我们在一个地方使用 SimpleDateFormat 显示 mm:ss 格式的时间。问题是我们在美国有一位客户抱怨他们将 5 分钟的格式设置为 35:00。我缩小了范围,SimpleDateFormat.format 被调用时使用的值与我正在测试的值相同,但它们的分钟数用 3 而不是 0 填充。

问题是我无法重现这个问题,他们告诉我他们已经测试并在 4 种不同的设备上得到它:

我也在,在小米 Mi A1(和其他一些)上进行测试,但是我尝试时时间还可以。

时间格式如下:

SimpleDateFormat timeFormatter = new SimpleDateFormat("mm:ss", Locale.getDefault());
timeFormatter.format(new Date(5*60*1000));

有人见过这样的东西吗?

这是时区问题。或者更准确地说,是将 SimpleDateFormat 用于不该用于的事情的问题。 您可以通过以下方式重现:

    TimeZone.setDefault(TimeZone.getTimeZone("America/St_Johns"));
    SimpleDateFormat timeFormatter = new SimpleDateFormat("mm:ss", Locale.getDefault());
    System.out.println(timeFormatter.format(new Date(5*60*1000)));

此片段的输出是:

35:00

解释: new Date(5*60*1000) 产生纪元后 5 分钟的日期时间,即 1970 年 1 月 1 日的 00:05:00 UTC。此时和其他任何时间一样,世界上不同的区域有不同的时间。但是,大多数时区与 UTC 有整数小时的偏移量。所以时间将是整点过后 5 分钟,您的格式化程序会将其打印为 05:00。这就是为什么你之前没有注意到这个问题。例如,在柏林,它将是前一天晚上的 01:05:00,而在纽约,它将是 19:05:00。但是,也有一些时区与 UTC 的偏移量不是整数小时。例如 Asia/Kolkata 在 +05:30,Asia/Kathmandu 在 +05:45。在这样的时区,时间不会整点过五分,你会得到你看到的意想不到的结果。

建议的解决方案包括:

  • 使用 TimeUnit 将秒转换为分钟和秒,使用 String.format 将它们分别格式化为两位数。
  • 如果您想要一个好的解决方案并且您可以接受在维护模式下对旧库的外部依赖,请查看 Joda-Time 的 PeriodFormatter

下面是使用 TimeUnit 计算要按照第一个项目符号中的建议格式化的部分的示例:

    long totalSeconds = TimeUnit.MINUTES.toSeconds(5); // 300

    long minutes = TimeUnit.SECONDS.toMinutes(totalSeconds);
    long secondsPart = totalSeconds - TimeUnit.MINUTES.toSeconds(minutes);
    String formattedDuration = String.format("%02d:%02d", minutes, secondsPart);
    System.out.println("Formatted duration: " + formattedDuration);

输出:

Formatted duration: 05:00

我不建议的丑陋技巧是将格式化程序的时区设置为 UTC。

我已经在评论中 link 回答的问题中有更多灵感。在撰写本文时,它有 20 个答案。我在底部重复 link。

顺便说一句,即使是格式化和解析日期和时间,您也可以考虑不使用SimpleDateFormat。众所周知,它很麻烦,而且早已过时。而是将 ThreeTenABP 添加到您的 Android 项目中,以便使用 java.time、现代 Java 日期和时间 API。与它一起工作要好得多。

链接