我的问题可能微不足道,但我只是在寻求澄清。我在SO中读到Java的Date()实际上总是在UTC时间,为什么当我创建一个Date()对象并使用toString()打印它时,它会显示本地时间。如果这不是打印它的正确方法,它应该是什么让我得到UTC时间?
答案 0 :(得分:7)
对于格式化,您应该使用DateFormat
实施(例如SimpleDateFormat
)。这将允许您指定时区(和输出格式)。 Date
本身没有时区概念 - 它代表了一个瞬间,使用“自Unix时代以来的毫秒”作为存储。 toString()
方法只使用系统默认时区将表示的任何瞬间转换为本地时间。
我个人建议完全放弃内置的日期/时间API,并使用Joda Time作为一个更明智的库。
答案 1 :(得分:1)
java.util.Date
对象仅表示自称为“纪元”的标准基准时间(即 1970 年 1 月 1 日 00 日)以来的 毫秒 数: 00:00 GMT(或UTC)。由于它不保存任何时区信息,它的 toString
函数应用 JVM 的时区返回一个 String
格式,EEE MMM dd HH:mm:ss zzz yyyy
,从这个 毫秒值。要以不同的格式和时区获取 String
对象的 java.util.Date
表示,您需要将 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("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String strDateNewYork = sdf.format(date);
System.out.println(strDateNewYork);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String strDateUtc = sdf.format(date);
System.out.println(strDateUtc);
}
}
输出:
2021-06-20T09:43:39.517-04:00
2021-06-20T13:43:39.517Z
java.util
日期时间 API 及其格式化 API SimpleDateFormat
已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*。
另外,下面引用的是来自 home page of Joda-Time 的通知:
<块引用>请注意,从 Java SE 8 开始,要求用户迁移到 java.time (JSR-310) - JDK 的核心部分,取代了该项目。
使用 java.time
(现代日期时间 API)的解决方案:
import java.time.Instant;
public class Main {
public static void main(String[] args) {
Instant now = Instant.now();
System.out.println(now);
}
}
输出:
2021-06-20T13:37:42.174352Z
Instant
表示 UTC 中时间线上的一个瞬时点。输出中的 Z
是零时区偏移的 timezone designator。它代表祖鲁语并指定 Etc/UTC
时区(时区偏移为 +00:00
小时)。
从 Trail: Date Time 了解有关现代 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。
答案 2 :(得分:0)
“ Java Date()以UTC返回日期”-实际上是什么意思?
UTC是我们调整全球时间的基准。
因为穴居人的日子是正午,所以正午或中午12:00。当然,这意味着在不同地方有不同的时刻。在日本,中午比欧洲早几个小时,而在美洲甚至更晚。
在现代时代,人类创造了time zones,其中午适用于大片土地,以至于太阳不可能同时覆盖所有土地。因此,太阳或“solar time”不再可以用来定义时间。现代时区定义为距基线一定小时数-分钟-秒。
什么基线?历史的命运将基线任意选择为贯穿Royal Observatory, Greenwich的纬度,遍及英国伦敦。东部的时区是UTC的某些小时-分钟-秒 ,而西部的时区是UTC的某些后。例如,印度比世界标准时间早五个半小时,而加勒比海马提尼克岛比世界标准时间晚四个小时。
如果偏移量是零时,分,秒,那么我们说我们处于“在UTC”或“在UTC”。
Java的Date()实际上总是在UTC时间
是的,java.util.Date
类尽管名称很不幸,但它代表的日期是一天中的时间,与UTC的偏移量是零。
顺便说一下,Date
类现在已过时。 java.time.Instant
类现在用作其替换,以表示UTC中的时刻。 Instant
的分辨率为nanoseconds,比Date
的{{3}}好。
当我创建一个Date()对象并使用toString()打印它时,它将显示本地时间
遗留日期时间类存在很多问题。如上所述,一种是较差的命名。另一个是不幸的设计决定所引起的良好意图,即Date::toString
应该在生成文本时动态应用JVM的当前默认时区,以根据UTC进行调整。这个错误的决定没有给Java程序员带来混乱和痛苦,因为它给人一种错觉,即java.util.Date
被分配了一个时区。
顺便说一句……更糟糕的是,java.util.Date
确实有一个时区,但是没有访问获取器/设置器方法,但深深地嵌入了源代码中。但是该区域确实会影响某些行为,例如确定此类对象之间的相等性。令人困惑?是。正如我所说的,这些传统的日期时间类充斥着糟糕的设计决策。
如果这不是正确的打印方式,那应该是什么,这样我才能获得UTC时间?
正确的方法是完全避免使用Date
类。只能使用 java.time 类。
➥要获取UTC当前时刻,请使用milliseconds。
Instant instant = Instant.now() ;
提示:如果您要更改时间以进行人工测试,请将备用Instant.now
传递给Clock
。
要生成一个String
的文本,该文本表示标准Instant.now( Clock )
格式的Instant
的值,只需调用toString
。幸运的是,该类不会像Date
那样注入时区。 ISO 8601方法说出了简单的真相,即UTC时刻的文本。
String output = instant.toString() ;
2019-12-03T10:15:30.032163Z
请注意,日期时间对象(例如Instant
)没有“格式”。只有表示那些对象值的文本才具有格式。文本和日期时间对象是不同的,并且彼此分开。日期时间对象可以生成此类文本,并且可以解析此类文本,但实际上不是该文本。
如果需要灵活性来生成其他格式的文本,请应用ZoneOffset
以获取OffsetDateTime
对象,或应用ZoneId
以获取ZonedDateTime
对象。应用DateTimeFormatter
对象以生成文本。
Instant::toString
框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧java.time日期时间类,例如legacy,java.util.Date
和Calendar
。
目前位于SimpleDateFormat
的Joda-Time项目建议迁移到maintenance mode类。
要了解更多信息,请参见java.time。并在Stack Overflow中搜索许多示例和说明。规格为Oracle Tutorial。
您可以直接与数据库交换 java.time 对象。使用符合JSR 310或更高版本的JDBC driver。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
How to use ThreeTenABP…项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如ThreeTen-Extra,Interval
,YearWeek
和YearQuarter
。