代码之家  ›  专栏  ›  技术社区  ›  curious1

Joda:将系统日期和时间转换为另一个区域中的日期/时间

  •  1
  • curious1  · 技术社区  · 7 年前

    我在SO读了很多帖子,并测试了其中的大部分。他们都不为我工作。这是我的代码:

    DateTimeZone fromTimeZone = DateTimeZone.forID("America/New_York");
    DateTimeZone toTimeZone = DateTimeZone.forID("US/Central");  
    Date now = new Date();        
    DateTime dateTime = new DateTime(now, fromTimeZone); 
    DateTime newDateTime = dateTime.withZone(toTimeZone);
    System.out.println(dateTime.toDate() + "--" + newDateTime.toDate());
    

    2017年8月22日星期二13:08:13——2017年8月22日星期二13:08:13

    我希望展示 "Tue Aug 22 12:08:13 CDT 2017" 第二个时区。

    1 回复  |  直到 7 年前
        1
  •  1
  •   user7605325 user7605325    7 年前

    A. java.util.Date doesn't have timezone information . 乔达的 DateTime 有,但它被包裹在一个 Chronology translate this instant to "human readable" date/time fields

    但最终,这两个物体只是 represent points (instants) in the time-line

    只需检查 dateTime.getMillis() newDateTime.getMillis() , dateTime.toDate().getTime() newDateTime.toDate().getTime() . 他们都会的 ,该值表示自epoch以来的毫秒数( 1970-01-01T00:00Z ).

    传递给 日期时间 对象只影响 toString() (当此毫秒值“转换”为本地日期和时间时),但不会更改毫秒值本身。因此,如果你这样做:

    DateTime dateTime = new DateTime(now, fromTimeZone);
    System.out.println(dateTime);
    

    fromTimeZone (美国/纽约):

    2017-08-22T13:33:08.345-04:00

    withZone keeps the same milliseconds value :

    DateTime newDateTime = dateTime.withZone(toTimeZone);
    System.out.println(newDateTime);
    

    上面的代码保留即时值(毫秒值),但在 toTimeZone (美国/中部):

    2017-08-22T12:33:08.345-05:00

    .toDate() 方法返回一个 System.out.println 隐式调用 Date::toString() method converts the milliseconds value to the JVM's default timezone . 在这种情况下,两者都是:


    如果你想得到 String 以特定格式包含日期的,可以使用 org.joda.time.format.DateTimeFormatter

    DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss z yyyy").withLocale(Locale.ENGLISH);
    System.out.println(fmt.print(new DateTime(DateTimeZone.forID("US/Central"))));
    

    没有必要转换dates对象,因为实际上没有发生任何转换:上述所有方法都不会更改毫秒值。

    还要注意,我使用了 java.util.Locale

    然后我得到当前日期并设置打印时使用的时区。注意,您可以获得 日期时间 Java语言util。日期 .

    输出将为:

    2017年8月22日星期二12:33:08 CDT

    要获得完全相同的输出(两个日期),可以执行以下操作:

    DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss z yyyy").withLocale(Locale.ENGLISH);
    DateTime nowNy = new DateTime(DateTimeZone.forID("America/New_York"));
    DateTime nowCentral = nowNy.withZone(DateTimeZone.forID("US/Central"));
    System.out.println(fmt.print(nowNy) + "--" + fmt.print(nowCentral));
    

    2017年8月22日星期二13:33:08——2017年8月22日星期二12:33:08 CDT


    Java新日期/时间API

    joda's website 它说: (如果您不想或无法从Joda迁移到另一个API,可以考虑本节) .

    如果您正在使用 ,考虑使用 new java.time API less bugged and less error-prone than the old APIs .

    如果您正在使用 Java<=7. ,您可以使用 ThreeTen Backport 安卓 ,这是 ThreeTenABP (更多关于如何使用它的信息 here

    下面的代码适用于这两种情况。 唯一的区别是包名(在Java 8中是 java.time org.threeten.bp ),但类和方法 姓名

    相关类别包括 DateTimeFormatter (将日期格式化为 一串 以特定格式), ZonedDateTime (表示特定时区中的日期和时间)和 ZoneId (代表时区):

    // formatter - use English locale for month and day of week
    DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
    
    // current date/time in New York timezone
    ZonedDateTime nowNy = ZonedDateTime.now(ZoneId.of("America/New_York"));
    // convert to another timezone (US/Central)
    ZonedDateTime nowCentral = nowNy.withZoneSameInstant(ZoneId.of("US/Central"));
    
    // format dates
    System.out.println(fmt.format(nowNy) + "--" + fmt.format(nowCentral));