Java的日期如何工作?

时间:2011-08-12 22:20:41

标签: java date

您好我在下面有以下代码:

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,而不管您的时区(最令人困惑的部分如何?)。上面的工作如何?我很困惑......

感谢。

3 个答案:

答案 0 :(得分:7)

您应该从不Date添加偏移量以创建另一个Date - 如果您只是 那么收到破碎的数据开始。

您应使用此代码。尝试以不是为其设计的方式处理java.util.Date是错误的代码。如果您想要表示特定时区的日期,请使用Calendar(urgh)或更好的Joda Time API。

特别是,您获得的代码将解决时区转换问题 - 因为date.getTimeZoneOffset()处的偏移量仍将date视为UTC(因为这就是它被定义为)甚至你视为本地日期/时间。

忽略Date.toString()显示的值 - 避免使用该方法。 使用SimpleDateFormat显示您感兴趣的时区的适当设置,或者(更好地,再次)使用Joda的DateTimeFormat类。

答案 1 :(得分:4)

java.time

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 中的以下函数来解决它:

  1. LocalDateTime#atZone(ZoneId)
  2. ZonedDateTime#withZoneSameInstant(ZoneId)

演示:

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 小时)。

ONLINE DEMO

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 desugaringHow to use ThreeTenABP in Android Project

答案 2 :(得分:1)

正如您所说,Date对象并不关心时区。它及时存储。只有在您想要显示日期时,时区才有意义。使用您要使用的特定时区的DateFormat来显示日期(使用setTimeZone