hh:mm a和HH:mm a之间的区别

10

这是我的原始代码-

String dateString = "23 Dec 2015 1:4 PM";
Locale locale = new Locale("en_US");
SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm a");
DateFormat df = new SimpleDateFormat("dd MMM yyyy HH:mm a", locale);
Date date = null;

try {
    date = formatter.parse(dateString);
} catch (ParseException e) {
    LOGGER.error(e);
}

String newDate = df.format(date);
System.out.println("oldDate = " + dateString);
System.out.println("newDate = " + newDate);

这是我的输出结果 -

oldDate = 23 Dec 2015 1:4 PM
newDate = 23 Dec 2015 01:04 AM

oldDatenewDate之间有上午下午差异。现在我将DateFormat代码更改为-

SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy hh:mm a");
DateFormat df = new SimpleDateFormat("dd MMM yyyy hh:mm a", locale);

然后我得到了预期的输出,即-

oldDate = 23 Dec 2015 1:4 PM
newDate = 23 Dec 2015 01:04 PM

我知道HH表示24小时格式,而hh表示12小时格式。

我的问题是:

如果我使用HH:mm a代替hh:mm a,这不应该返回24小时格式的时间吗?

(或者)

如果它默认为12小时格式,它不应该根据提供的日期输入返回相应的上午/下午标记吗?

这只是为了让我理解。

3个回答

21

更新的答案

问题在于程序的流程控制(Program flow)。

SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm a");

这个简单日期格式化程序用于格式化创建的日期字符串的Date对象,以下是答案的重要部分

如果您使用HH而不是hhSimpleDateFormater则认为提供的日期字符串采用24小时制,并且简单地忽略了上午/下午标记

从此SimpleDateFormatter构造的日期对象传递给

DateFormat df = new SimpleDateFormat("dd MMM yyyy HH:mm a", locale);

这就是为什么它在打印

newDate = 23 Dec 2015 01:04 AM

如果你改变这行

SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm a");

随着

SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy hh:mm a");

一切都会顺其自然!

注意:创建本地化时,应将语言代码传递给Locale()构造函数。使用en-us而不是en_us

重要提示:代码已在Java 8上测试通过。 Java(TM) SE Runtime Environment (build 1.8.0_121-b13)


感谢@MenoHochschild。请再次查看我的答案! - Shinde Arjun
1
好一些了,但推荐使用 new Locale("en-us") 仍然是错误的。 - Meno Hochschild
@MenoHochschild,恕我直言,我想知道我们如何从我的答案中所述的语言构建一个Java 8(1.8.0_121)的Locale! - Shinde Arjun
请查看Java 8包java.util.Locale中的代码片段,第700行清楚地说明我们可以从语言构建Locale。我正在参考Java 8(1.8.0-121)版本。 - Shinde Arjun
我甚至使用过1.8.0-131版本。问题是:“en-us”只是一个语言代码,而没有指向美国的国家(方法getCountry()为空!)。显然,“en-us”在JRE的深度堆栈中以某种方式被解释为英语,因此让您认为它会起作用。并且API非常清晰,单参数区域设置构造函数仅使用纯语言参数...而不是国家。如果需要确定依赖于国家的周规则(在美国或英国不同),这一点很重要。 - Meno Hochschild

11

hh:mm 与 HH:mm 的区别:

  HH:mm => will look like 00:12, 23:00... this has 24 hour format.

  hh:mm => will look like 01:00Am, 02:00Am,...01:00pm this has 12 hour format.

在 hh:mm a 或 HH:mm a 中,a 是 Am/pm 标记。欲了解更多信息,请访问链接


1

一个简单的测试可以最好地解释“HH:mm a”模式的含义。首先,让我们研究打印模式

旧格式引擎SimpleDateFormat

Calendar cal = new GregorianCalendar(2015, 3, 1, 17, 45);
SimpleDateFormat sf = new SimpleDateFormat("HH:mm a", Locale.US);
System.out.println(sf.format(cal.getTime())); // 17:45 PM

Java-8(使用新包java.time.format):
LocalTime time = LocalTime.of(17, 59);
DateTimeFormatter tf = DateTimeFormatter.ofPattern("HH:mm a", Locale.US);
System.out.println(tf.format(time)); // 17:59 PM

这里两种情况都没有覆盖任何重写。我更喜欢这种方法,因为在我的观点中,使用“HH”和“a”的组合更多地表明了编程错误(用户显然没有足够地思考这些模式符号的含义和官方描述)。
现在让我们研究解析模式(我们将使用严格模式观察幕后发生了什么):
String dateString = "23 Dec 2015 1:4 PM";
SimpleDateFormat df = new SimpleDateFormat("dd MMM yyyy H:m a", Locale.US);
df.setLenient(false);
Date date = df.parse(dateString);
// java.text.ParseException: Unparseable date: "23 Dec 2015 1:4 PM"

Java-8中的行为与以前相同,但具有更清晰的错误消息:
DateTimeFormatter tf = DateTimeFormatter.ofPattern("H:m a", Locale.US);
tf = tf.withResolverStyle(ResolverStyle.STRICT);
LocalTime.parse("1:4 PM", tf);
// DateTimeException: Cross check failed: AmPmOfDay 0 vs AmPmOfDay 1

这条信息告诉我们,解析出的小时数(24小时制!)为“1”表示上午,而文本输入包含另一个解析出的AM/PM值“PM”。这种歧义无法解决。
教训是:在宽容解析可能忽略矛盾信息并导致错误假设时,我们必须小心。@Arjun的答案完全是错的。
顺便说一下:请使用Locale.US或new Locale("en", "US")代替new Locale("en-US"),因为语言"en-US"不存在。

你好@MenoHochschild,请看一下这个答案!感谢您的建设性批评!我想听听您的意见! - Shinde Arjun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接