如何从字符串中解析时间(小时、分钟)?

How to parse time (hour, minute) from a string?

任何人都知道如何从看起来像 "01:20" -> 1:20AM 和 "21:20" -> [= 的字符串中解析时间(小时、分钟和 AM/PM) 28=]?大多数解决方案似乎都假定或需要一个 Date 或 Calendar 对象。

我的输入时间实际上来自 TimePickerDialog(具体来说,this MaterialDateTimePicker implementation,所以我只收到 hourOfDay、分钟和秒(整数)。

我希望能够以友好的方式格式化用户选择的时间,即 12:30PM、02:15AM 等

我正在尝试使用 Joda Time:

fun formattedTime(timeStr: String): String {
    // Get time from date
    val timeFormatter = DateTimeFormat.forPattern("h:mm a")
    val displayTime = timeFormatter.parseLocalTime(timeStr)
    return displayTime.toString()
}

但我在输入字符串(如“1:20”)时遇到此错误: java.lang.IllegalArgumentException: Invalid format: "1:20" is too short

我也调查过SimpleDateFormat but it seems to require a full date-time string such as in this related question

正如@ole-v-v 指出的那样,SimpleDateFormat 已经有了更好的日子 - 所以今天你可以利用 java.time 包来完成这项工作:

java.time.format.DateTimeFormatter target2 = 
     java.time.format.DateTimeFormatter.ofPattern("h:mm a");
java.time.format.DateTimeFormatter source2 = 
     java.time.format.DateTimeFormatter.ofPattern("HH:mm");

System.out.println("01:30 -> " + target2.format(source2.parse("01:30")));
System.out.println("21:20 -> " + target2.format(source2.parse("21:20")));

产生

的结果
01:30 -> 1:30 AM
21:20 -> 9:20 PM

符合预期。

在 Joda-Time 中,您可以按照@meno-hochschild 在他下面的回答中指出的那样对其进行编码。

使用 SimpleDateFormat 将如下所示:

    SimpleDateFormat target = new SimpleDateFormat("h:mm a");
    SimpleDateFormat source = new SimpleDateFormat("HH:mm");
    System.out.println("01:30 -> " + target.format(source.parse("01:30")));
    System.out.println("21:20 -> " + target.format(source.parse("21:20")));

这将从 24 小时解析为 12 小时显示

    01:30 -> 1:30 AM
    21:20 -> 9:20 PM      

这完全取决于小时的格式 - 对于解析,您需要 24 小时(格式 HH),对于输出,您需要 12 小时加上上午/下午 - 格式为 h。

如果您希望 01:30 成为 PM,您必须将其添加到要以某种方式解析的字符串中:

   System.out.println("01:30 pm-> " + target.format(target.parse("01:30 pm")));

导致

   01:30 pm-> 1:30 PM

接受的答案是正确的。然而,我很惊讶地看到旧的 类 像 SimpleDateFormat 尽管 OP 明确首先需要一个 Joda 答案(见问题的标签)。所以我 post 将 Joda 的答案作为补充:

DateTimeFormatter target = DateTimeFormat.forPattern("h:mm a").withLocale(Locale.ENGLISH);
DateTimeFormatter source = DateTimeFormat.forPattern("HH:mm");
System.out.println("01:30 -> " + target.print(source.parseLocalTime("01:30")));
System.out.println("21:20 -> " + target.print(source.parseLocalTime("21:20")));

01:30 -> 1:30 AM
21:20 -> 9:20 PM

我建议不要混合使用两个不同的时间库(OP 显然使用 Joda-Time-Android)。

您的两个不错的选择是 Joda-Time 和 java.time

由于您从时间选择器接收到整数形式的 hourOfDay、分钟和秒,因此无需进行任何解析。

java.time

    DateTimeFormatter timeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
            .withLocale(Locale.US);
    LocalTime time = LocalTime.of(hourOfDay, minute, second);
    String displayTime = time.format(timeFormatter);
    System.out.println(displayTime);

这样打印时间:

11:45 PM

我依赖于美国语言环境的内置本地化格式,而不是显式格式模式字符串。它在分钟和 PM(或 AM)之间放置了一个 space。我相信您的用户会对此感到高兴。如果没有,您将需要改用 DateTimeFormatter.ofPattern("h:mma", Locale.US)

乔达时间

如果您已经在使用 Joda-Time 并且此时没有理由更改,那么坚持使用它是合理的。您可以使用 LocalTime(int hourOfDay, int minuteOfHour, int secondOfMinute) 构造函数。然后按照 中的方式进行。这是一个很好且知识渊博的答案。

Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).

(引自the Joda-Time homepage

远离 SimpleDateFormat

远离 SimpleDateFormat class。它可以为工作工作,但它不仅已经过时,而且出了名的麻烦。

问题:我可以在 Android 上使用 java.time 吗?

是的,java.time 在新旧 Android 设备上都能很好地工作。只需要至少 Java 6.

  • 在 Java 8 和更高版本以及较新的 Android 设备上(据我所知,来自 API 级别 26)现代 API 是内置的。
  • 在 Java 6 和 7 中获取 ThreeTen Backport,新 classes 的 backport(ThreeTen 用于 JSR 310;请参阅底部的链接)。
  • 在(较旧的)Android 使用 ThreeTen Backport 的 Android 版本。它叫做 ThreeTenABP。并确保使用子包从 org.threeten.bp 导入日期和时间 classes。

链接