您好我在下面有以下代码:
public Date convertFromGMTToLocal(Date date) {
return new Date(date.getTimezoneOffset() + newOffset*60*1000);
}
public Date convertFromLocalToGMT(Date date) {
return new Date(date.getTime() - date.getTimezoneOffset()*60*1000);
}
convertFromLocalToGMT应该剥离时区信息,convertFromGMTToLocal应该返回时区信息。我知道java.util.Date表示epoch中的时间并且总是在GMT中,但是当显示日期时,它默认为JVM的默认时区。
解释我得到的是,如果您的时区是CST并且是CST上午10:00您正在使用convertFromLocalToGMT将时区更改为GMT,那么您实际上是要添加偏移量以获得GMT,以便获得4:00 AM CST(偏移量为 - 6)并且使用convertFromGMTToLocal将将此Date对象转换回上午10:00,而不管您的时区(最令人困惑的部分如何?)。上面的工作如何?我很困惑......
感谢。
答案 0 :(得分:7)
您应该从不向Date
添加偏移量以创建另一个Date
- 如果您只是 那么收到破碎的数据开始。
您应不使用此代码。尝试以不是为其设计的方式处理java.util.Date
是错误的代码。如果您想要表示特定时区的日期,请使用Calendar
(urgh)或远更好的Joda Time API。
特别是,您获得的代码将不解决时区转换问题 - 因为date.getTimeZoneOffset()
处的偏移量仍将date
视为UTC(因为这就是它被定义为)甚至你将视为本地日期/时间。
忽略Date.toString()
显示的值 - 避免使用该方法。 使用SimpleDateFormat
显示您感兴趣的时区的适当设置,或者(更好地,再次)使用Joda的DateTimeFormat
类。
答案 1 :(得分:4)
java.util
日期时间 API 及其格式化 API SimpleDateFormat
已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*。
另外,下面引用的是来自 home page of Joda-Time 的通知:
<块引用>请注意,从 Java SE 8 开始,要求用户迁移到 java.time (JSR-310) - JDK 的核心部分,取代了该项目。
您可以使用现代日期时间 API java.time
中的以下函数来解决它:
演示:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
/*
* Change the JVM's ZoneId, ZoneId.systemDefault() to the required ZoneId e.g. ZoneId.of("America/New_York")
*/
public class Main {
public static void main(String[] args) {
// Test
ZoneId zoneId = ZoneId.of("Etc/UTC");
ZonedDateTime zdt = ZonedDateTime.of(LocalDate.of(2021, 5, 10), LocalTime.of(15, 20), zoneId);
System.out.println(zdt + " is " + convertFromZdtToLdt(zdt) + " at " + ZoneId.systemDefault().getId());
LocalDateTime ldt = LocalDateTime.of(LocalDate.of(2021, 5, 10), LocalTime.of(15, 20));
System.out
.println(ldt + " at " + ZoneId.systemDefault().getId() + " is " + convertFromLdtZdtToZdt(ldt, zoneId));
}
public static LocalDateTime convertFromZdtToLdt(ZonedDateTime zdt) {
return zdt.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
}
public static ZonedDateTime convertFromLdtZdtToZdt(LocalDateTime ldt, ZoneId targetZoneId) {
return ldt.atZone(ZoneId.systemDefault()).withZoneSameInstant(targetZoneId);
}
}
我在欧洲/伦敦时区的系统上的输出:
2021-05-10T15:20Z[Etc/UTC] is 2021-05-10T16:20 at Europe/London
2021-05-10T15:20 at Europe/London is 2021-05-10T14:20Z[Etc/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 :(得分:1)
正如您所说,Date对象并不关心时区。它及时存储。只有在您想要显示日期时,时区才有意义。使用您要使用的特定时区的DateFormat
来显示日期(使用setTimeZone)