【问题标题】:Get same date in different timezone在不同的时区获取相同的日期
【发布时间】:2020-03-17 04:29:49
【问题描述】:

我有一个 epochmilli sec 时间。 从这个纪元时间创建了一个日期对象。

Date date = new Date(epochMilli);

假设日期是"23 Nov 2019 00:00:00"

现在,我只想在不同的时区获得相同的日期,例如:]

日本时间:2019 年 11 月 23 日 00:00:00

美国时间:2019 年 11 月 23 日 00:00:00

我目前正在使用LocalDateTimeZonedDateTime

但是当我转换到不同的区域时,时间也会改变。但我不希望这个时间改变。

提前致谢。

【问题讨论】:

  • 你能告诉我们你用过的epochMilli的值吗?
  • 时间应该从一个区域到另一个区域,你正在搜索的内容是不可能的
  • epockMilli 值:1574208000000L
  • @JochenReinhardt 我 OP想要ZonedDateTimes的日期"23 Nov 2019 00:00:00"在不同的时区,这意味着他想要不同的瞬间都显示相同的日期和时间.但我们不能确定这一点......
  • 只需转换为LocalDate。这是一个没有时间和时区的日期,所以我认为它应该为您提供独立于时区的东西。我建议您远离您也在问题中使用的 Date 类。它的设计很糟糕,而且已经过时了,你没有用它。

标签: java date timezone localdate zoneddatetime


【解决方案1】:

不幸的是,您没有向我们展示如何您使用 ZonedDateTime,因此以下示例可能会比您想要的更多,通过展示如何解析毫秒,将生成的日期时间从 1 zone 到其他人以及如何使用不同的区域解析日期时间:

public static void main(String[] args) {

    long epochMillis = 1574208000000L;
    
    // define a formatter to be used
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss",
                                                        Locale.ENGLISH);

    // create an instant from the milliseconds
    Instant instant = Instant.ofEpochMilli(epochMillis);
    // and create some example time zones for later use
    ZoneId utc = ZoneId.of("UTC");
    ZoneId tokyo = ZoneId.of("Asia/Tokyo");
    ZoneId losAngeles = ZoneId.of("America/Los_Angeles");
    ZoneId chicago = ZoneId.of("America/Chicago");
    
    /*
     * Part 1: Getting the date time converted to different time zones
     */
    
    // use the instant to create a ZonedDateTime at a specific time zone, here: UTC
    ZonedDateTime utcZdt = instant.atZone(utc);

    // then take the UTC-ZonedDateTime as base for conversion to other time zones 
    ZonedDateTime asiaTokyoConvertedfromUtc = utcZdt.withZoneSameInstant(tokyo);
    ZonedDateTime americaLosAngelesConvertedfromUtc = utcZdt.withZoneSameInstant(losAngeles);
    ZonedDateTime americaChicagoConvertedfromUtc = utcZdt.withZoneSameInstant(chicago);

    // print the results
    System.out.println("#### 1574208000000L at UTC, converted to other zones ####");
    System.out.println("UTC time zone:\t\t\t\t" + utcZdt.format(dtf));
    System.out.println("JST (Japan/Tokyo) time zone:\t\t"
                        + asiaTokyoConvertedfromUtc.format(dtf));
    System.out.println("PST (USA/Los Angeles) time zone:\t"
                        + americaLosAngelesConvertedfromUtc.format(dtf));
    System.out.println("CST (USA/Chicago) time zone:\t\t"
                        + americaChicagoConvertedfromUtc.format(dtf));
    
    System.out.println();

    /*
     * Part 2: Getting the date time in different time zones
     */
    
    // use the instant to create a ZonedDateTime at Asia/Tokyo
    ZonedDateTime asiaTokyoFromMillis = instant.atZone(tokyo);

    // use the instant to create a ZonedDateTime at America/Los Angeles
    ZonedDateTime americaLosAngelesFromMillis = instant.atZone(losAngeles);

    // use the instant to create a ZonedDateTime at America/Chicago
    ZonedDateTime americaChicagoFromMillis = instant.atZone(chicago);

    // print the (expected) results, same as converted date times...
    System.out.println("#### 1574208000000L at different zones ####");
    System.out.println("UTC time zone:\t\t\t\t" + utcZdt.format(dtf));
    System.out.println("JST (Asia/Tokyo) time zone:\t\t"
                        + asiaTokyoFromMillis.format(dtf));
    System.out.println("PST (USA/Los Angeles) time zone:\t"
                        + americaLosAngelesFromMillis.format(dtf));
    System.out.println("CST (USA/Chicago) time zone:\t\t"
                        + americaChicagoFromMillis.format(dtf));
    
    System.out.println();
    
    /*
     * Part 3: How to parse the date time instead of millis
     */
    
    // provide a parseable date time String
    String dateTime = "23 Nov 2019 00:00:00";
    
    // parse it in each desired time zone
    ZonedDateTime utc23Nov2019 = LocalDateTime.parse(dateTime, dtf).atZone(utc);
    ZonedDateTime asiaTokyo23Nov2019 = LocalDateTime.parse(dateTime, dtf)
                                                    .atZone(tokyo);
    ZonedDateTime americaChicago23Nov2019 = LocalDateTime.parse(dateTime, dtf)
                                                         .atZone(losAngeles);
    ZonedDateTime americaLosAngeles23Nov2019 = LocalDateTime.parse(dateTime, dtf)
                                                            .atZone(chicago);

    // print the results, now you have the 23. Nov 2019 at 00:00:00 at each time zone
    System.out.println("#### \"23 Nov 2019 00:00:00\" at different zones ####");
    System.out.println("UTC time zone:\t\t\t\t" + utc23Nov2019.format(dtf));
    System.out.println("JST (Asia/Tokyo) time zone:\t\t"
                        + asiaTokyo23Nov2019.format(dtf));
    System.out.println("PST (USA/Los Angeles) time zone:\t"
                        + americaChicago23Nov2019.format(dtf));
    System.out.println("CST (USA/Chicago) time zone:\t\t"
                        + americaLosAngeles23Nov2019.format(dtf));
}

这个的输出是

#### 1574208000000L at UTC, converted to other zones ####
UTC time zone:                      20 Nov 2019 00:00:00
JST (Japan/Tokyo) time zone:        20 Nov 2019 09:00:00
PST (USA/Los Angeles) time zone:    19 Nov 2019 16:00:00
CST (USA/Chicago) time zone:        19 Nov 2019 18:00:00

#### 1574208000000L at different zones ####
UTC time zone:                      20 Nov 2019 00:00:00
JST (Asia/Tokyo) time zone:         20 Nov 2019 09:00:00
PST (USA/Los Angeles) time zone:    19 Nov 2019 16:00:00
CST (USA/Chicago) time zone:        19 Nov 2019 18:00:00

#### "23 Nov 2019 00:00:00" at different zones ####
UTC time zone:                      23 Nov 2019 00:00:00
JST (Asia/Tokyo) time zone:         23 Nov 2019 00:00:00
PST (USA/Los Angeles) time zone:    23 Nov 2019 00:00:00
CST (USA/Chicago) time zone:        23 Nov 2019 00:00:00

【讨论】:

  • 辛苦了!您可以通过这种方式使其更简单:Instant utcFromMillis = Instant.ofEpochMilli(epochMillis); ZonedDateTime asiaTokyoConvertedfromUtc = utcFromMillis.atZone(ZoneId.of("Asia/Tokyo"));.
  • 我只是快速浏览了一下,发现还有一件事要改变。正如我在第一条评论中建议的那样,最好将ZonedDateTime asiaTokyoConvertedfromUtc = utcZdt.toInstant().atZone(tokyo); 更改为ZonedDateTime asiaTokyoConvertedfromUtc = instant.atZone(tokyo);。您甚至可以将 ZonedDateTime utcZdt = ZonedDateTime.ofInstant(instant, utc); 更改为 ZonedDateTime utcZdt = instant.atZone(utc); 以使其与接下来的三个语句保持一致(一旦您按照我的建议更新了它们)。
  • @ArvindKumarAvinash 再次感谢,我在上次编辑中考虑了这两个建议。
  • 看完之后感觉这个演示只需要两个部分。我已经重写了这个程序here。请将其与您当前的代码进行比较并随意使用它(最终,我们的目标是为开发人员/学习者提供最佳解决方案和建议)。
  • 好吧,@ArvindKumarAvinash,你基本上是对的,因为你是一个习惯于这个库的经验丰富的开发人员。但我的目标是展示不同的情况。第一个有一个long 作为基础,第二个有ZonedDateTime,第三个有String。一个答案可能太多了,但我认为这是最常见的情况。
【解决方案2】:

旧版java.util.Date 不支持时区。它基本上是自 1970 年 1 月 1 日 0:00 以来以毫秒为单位测量的时间点。没有别的了。

打印日期时,会使用系统的默认区域设置和时区对其进行格式化。为了获得针对不同时区格式化的 java.util.Date 对象,您必须相应地配置您的 DateFormat

Date pointInTime = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance();
dateFormat.setTimeZone(TimeZone.getTimeZone("PST"));
System.out.println(dateFormat.format(pointInTime));
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(dateFormat.format(pointInTime));

使用更新的 LocalDate API,情况有所不同。上一个答案给出了一个丰富的例子。

【讨论】:

  • 我们不仅不应该使用DateDateFormatTimeZone。这些课程设计不良且早已过时。我们也不应该依赖或尝试解析三个字母的时区缩写。他们是模棱两可的,我想更多的是。像 Asia/Manilla 或 Pacific/Pitcairn 一样使用,即 region/city 作为时区 ID。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-20
相关资源
最近更新 更多