将日期转换为东部时间 - 获取日期对象作为输出

Convert date to Eastern Time - Get Date object as output

我见过很多将日期从一个时区转换为另一个时区的例子。但它们都以字符串形式输出。我想要一个日期对象作为输出。

我试过的方法 -

方法一

SimpleDateFormat dateTimeFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a z");
dateTimeFormat.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
Date date = new Date();

System.out.println(dateTimeFormat.format(date)); // this print IST Timezone

DateFormat timeFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a z");
timeFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));

String estTime = timeFormat.format(date);
try {
    date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a z", Locale.ENGLISH).parse(estTime);
    System.out.println(date);

    } catch (ParseException ex) {
    Logger.getLogger(A.class.getName()).log(Level.SEVERE, null, ex);
}


System.out.println(timeFormat.format(date));

方法二

private static Date shiftTimeZone(Date date, TimeZone sourceTimeZone, TimeZone targetTimeZone) {
        System.out.println(sourceTimeZone.toString());
        System.out.println(targetTimeZone.toString());
        Calendar sourceCalendar = Calendar.getInstance();
        sourceCalendar.setTime(date);
        sourceCalendar.setTimeZone(sourceTimeZone);

        Calendar targetCalendar = Calendar.getInstance();
        for (int field : new int[]{Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, Calendar.HOUR, Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND}) {
            targetCalendar.set(field, sourceCalendar.get(field));
        }
        targetCalendar.setTimeZone(targetTimeZone);

        return targetCalendar.getTime();
    }

方法 1 以字符串形式给出结果。

03/22/2018 10:16:57 AM EDT <- instanceOf String

方法 2 给我正确的东部时间时区日期和时间,但日期具有 IST 时区。

Thu Mar 22 10:16:57 IST 2018 <- instanceof Date

任何人都可以帮我获得一个东部时区的日期对象。

更新-我的最终目标是获取当前东部时间的Unix时间戳。

tl;博士

Instant.now()                        // Capture the current moment in UTC, an `Instant` object.
    .atZone(                         // Adjust from UTC into a particular time zone.
        ZoneId.of( “Asia/Kolkata” ) 
    )                                // Returns a `ZonedDateTime` object. 
    .withZoneSameInstant(            // Adjust into yet another time zone. All three are the same moment but vowed using different wall-clock times. 
        ZoneId.of( “Africa/Tunis” ) 
    )                                // Returns another `ZonedDateTime` object. 

或者……

ZonedDateTime.now( 
    ZoneId.of( “Asia/Kolkata” )
).withZoneSameInstant(
    ZoneId.of( “Africa/Tunis” )
)

避免遗留 date-time classes

首先,停止使用旧版 date-time classes。他们真是一团糟。由 java.time classes.

补充
  • Date 替换为 Instant.
  • Calendar 替换为 ZonedDateTime
  • SimpleDateFormat 替换为 DateTimeFormatter.

Date::toString

骗了

其次,了解 Date 有一个非常令人困惑的功能,即在生成字符串时动态应用 JVM 当前的默认时区。 Date 始终表示 UTC 中的时刻。 toString 方法会造成 Date 带有时区的错误幻觉,而实际上它的值在世界标准时间。尽管 class 设计师 well-intentioned 做出了这个决定,但这是一个灾难性的决定,几十年来一直在无数程序员中造成混乱。

更糟糕的是:实际上 一个隐藏在 Date 中的时区,但与本次讨论无关。令人困惑?是的;正如我所说,糟糕的设计真是一团糟。

Instant

Instant class 替换 Date 更清楚。 Instant 表示一个时刻,时间轴上的一个点,始终采用 UTC,分辨率为纳秒。

使用 Instant 以 UTC 格式捕获当前时刻。 JVM 当前的默认时区无关紧要。主机 OS' 分配的时区无关紧要。

Instant instant = Instant.now() ;  // Capture the current moment in UTC. 

Date::toString不同,Instant::toString方法说的是实话。 Instant 始终采用 UTC,因此 toString 始终报告 UTC。字符串以标准 ISO 8601 格式生成。最后的 ZZulu 的缩写,表示 UTC。

instant.toString(): 2018-01-23T12:34:56.123456789Z

关于捕获当前时刻...在 Java 8 中,即使 java.time classes可以 表示 纳秒。在 Java 9 及更高版本中,Clock 的新实现提供了以更精细的粒度捕获当前时刻。在 Java 9.0.4 on macOS Sierra 中,我看到了微秒。如今,传统计算机上的硬件时钟无法以微秒级以上的精度捕捉当前时刻。

ZonedDateTime

要通过特定地区人们使用的 wall-clock 时间的镜头查看同一时刻,请指定该地区的时区。将 ZoneId 应用于 Instant 会产生 ZonedDateTime。概念上:

ZonedDateTime = ( Instant + ZoneId )

在代码中:

ZoneId z = ZoneId.of( “Pacific/Auckland” ) ;
ZonedDateTime zdt = instant.atZone( z ) ;   // Same moment, same point on the timeline, different wall-clock time. 

适应另一个时区很容易。您可以再次从 Instant 开始。

ZoneId zKolkata = ZoneId.of( “Asia/Kolkata” ) ;
ZonedDateTime zdt = instant.atZone( zKolkata ) ;  

或者您可以调整 ZonedDateTime 对象。 java.time class 使用不可变对象。因此,调整不会“改变”(改变)原始对象,而是产生一个新的不同对象。

ZonedDateTime zdtKolkata = zdt.withZoneSameInstant( zKolkata ) ;  // Same moment, same point on the timeline, different wall-clock time. 

您可以跳过 Instant 的使用。我不建议这样做。程序员应该在 UTC 中思考、调试、记录日志、交换数据以及大部分业务逻辑。所以 Instant 应该是你的 go-to class 每当你开始使用 date-time 值时。

ZonedDateTime zdtNewYork = ZonedDateTime.now( ZoneId.of( "America/New_York" ) ) ;

ZonedDateTime::toString 方法通过在方括号中附加时区名称,明智地扩展了 ISO 8601 标准。

String output = zdtNewYork.toString() ;

2018-01-23T07:34:56.123456789-05:00[America/New_York]


关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

您可以直接与数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* classes.

从哪里获得java.time classes?

  • Java SE 8, Java SE 9,及以后
    • Built-in。
    • 标准 Java API 的一部分,带有捆绑实施。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6 and Java SE 7
    • java.time 的大部分功能是 back-ported 到 Java ThreeTen-Backport 中的 6 和 7。
  • Android
    • Android java.time classes.
    • 捆绑实施的更高版本
    • 对于较早的 Android (<26),ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See .

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.