java.time
Answer by Jon Skeet 是正确的。这里更新了一些代码以使用现代的 java.time 类,这些类取代了麻烦的旧日期时间类。
格式化模式
定义格式模式以匹配您的输入。
顺便说一句,您的格式选择不佳。相反,我建议使用标准的 ISO 8601 格式,用于将日期时间值交换为文本。
12 小时制与 24 小时制
您的输入数据或格式模式存在缺陷。您使用了小写的h,这意味着在 12 小时制中一个小时的一个或两个数字(而不是 24 小时制,即大写的 H 或 HH)。因此,除非您添加AM 或PM 的指示符,否则您的输入毫无意义。我会假设你错误地从你的问题代码中省略了这个。
Locale locale = Locale.US ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu h:m a" ).withLocale( locale ) ;
LocalDateTime
解析 LocalDateTime 对象之类的字符串,因为它们缺少预期时区的指示符或与 UTC 的偏移量。
String input = "23/01/2020 4:5 PM" ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
ldt.toString(): 2020-01-23T16:05
时刻
我们上面得到的LocalDateTime 对象确实不代表一个时刻,不是时间轴上的一个点。我们的时间是 23 日下午 4 点左右。但我们不知道这是否意味着东京、图卢兹或托莱多的下午 4 点——所有这些时刻相隔几个小时。
要确定某个时刻,我们必须确定预期的时区。然后将该区域应用为ZoneId 以获得ZonedDateTime。然后我们就到了。
Locale 不是时区
我的设备的区域设置到任何地方
Locale 与时区没有。 Locale 用于本地化生成的表示日期时间对象的文本。
要本地化,请指定:
例子:
Locale l = Locale.CANADA_FRENCH ; // Or Locale.US, Locale.JAPAN, etc.
DateTimeFormatter f =
DateTimeFormatter
.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( l )
;
String output = myZonedDateTime.format( f );
您可能有一位来自魁北克的工程师,他使用Locale.CANADA_FRENCH 来表示人类语言和文化规范,但在日本访问时使用Asia/Tokyo 时区来安排约会。
ZonedDateTime
回到你的LocalDateTime 对象。如果您确定它是为了代表突尼斯挂钟时间中的某个时刻,则应用Africa/Tunis 时区。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
你问:
设备如何知道我给它的日期是哪个时区,以便它进行相应的计算?
您使用了糟糕的日期时间类,未能解释缺少时区指示符或与 UTC 偏移的日期时间的概念。所以从技术上讲,你的代码是一团糟,一个黑客,在 Joda-Time 和它的继任者 java.time 之前的那些日子里是不可避免的。
我建议花不努力去理解Date 和Calendar 的行为。继续使用 java.time,这是业界领先的日期时间处理框架。