不知不觉中,您在代码中引入了两个主要问题:
-
未使用正确的时区名称:两个/三个/四个字母的时区名称(例如 ET、EST、CEST 等)容易出错。 proper way of naming a timezone 是 Region/City 例如欧洲/伦敦。在大多数情况下,Region 是 City 所属大陆的名称。
-
不使用
Locale 和 SimpleDateFormat:解析/格式化类型,例如旧版SimpleDateFormat 或现代版DateTimeFormatter 对Locale 敏感,因此您应该始终使用Locale 以避免意外。您可以查看this answer 了解更多信息。
另外,请注意java.util.Date 对象不是像modern Date-Time types 那样的真实日期时间对象;相反,它表示自称为“纪元”的标准基准时间以来的毫秒数,即January 1, 1970, 00:00:00 GMT(或 UTC)。由于它不包含任何格式和时区信息,它应用格式 EEE MMM dd HH:mm:ss z yyyy 和 JVM 的时区来返回从该毫秒值派生的 Date#toString 的值。如果您需要以不同的格式和时区打印日期时间,则需要使用具有所需格式和适用时区的SimpleDateFormat,例如
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy hh:mm a zzz", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println(sdf.format(date));
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println(sdf.format(date));
}
}
示例输出:
05/06/21 08:29 AM EDT
05/06/21 12:29 PM UTC
ONLINE DEMO
java.time
java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用,改用modern Date-Time API*。
使用现代 API java.time 的演示:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
Instant now = Instant.now();
System.out.println(now);
ZonedDateTime zdtUTC = now.atZone(ZoneId.of("Etc/UTC"));
System.out.println(zdtUTC);
ZonedDateTime zdtNewYork = now.atZone(ZoneId.of("America/New_York"));
System.out.println(zdtNewYork);
}
}
示例输出:
2021-06-05T12:19:58.092338Z
2021-06-05T12:19:58.092338Z[Etc/UTC]
2021-06-05T08:19:58.092338-04:00[America/New_York]
ONLINE DEMO
需要不同格式的输出字符串?
您可以将DateTimeFormatter 用于不同格式的输出字符串,例如
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
Instant now = Instant.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/MM/uu hh:mm a zzz", Locale.ENGLISH);
ZonedDateTime zdtUTC = now.atZone(ZoneId.of("Etc/UTC"));
System.out.println(dtf.format(zdtUTC));
ZonedDateTime zdtNewYork = now.atZone(ZoneId.of("America/New_York"));
System.out.println(dtf.format(zdtNewYork));
}
}
示例输出:
05/06/21 12:34 PM UTC
05/06/21 08:34 AM EDT
ONLINE DEMO
在这里,您可以使用yy 代替uu,但可以使用I prefer u to y。
从Trail: Date Time了解更多关于java.time的modern Date-Time API*。
* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 和 7 . 如果您正在为一个 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring 和 How to use ThreeTenABP in Android Project。