【问题标题】:JodaTime - how to get current time in UTCJodaTime - 如何以 UTC 获取当前时间
【发布时间】:2015-01-02 11:18:59
【问题描述】:

我想以 UTC 格式获取当前时间。到目前为止我所做的如下(仅用于测试目的):

    DateTime dt = new DateTime();
    DateTimeZone tz = DateTimeZone.getDefault();
    LocalDateTime nowLocal = new LocalDateTime();
    DateTime nowUTC = nowLocal.toDateTime(DateTimeZone.UTC);

    Date d1 = nowLocal.toDate();
    Date d2 = nowUTC.toDate();

    L.d("tz: " + tz.toString());
    L.d("local: " + d1.toString());
    L.d("utc: " + d2.toString());
  • d1 是我的当地时间,没关系
  • d2 是我的当地时间 + 1,但应该是当地时间 - 1...

我的本​​地时区是 UTC+1(根据调试输出和此处的列表:https://www.joda.org/joda-time/timezones.html)...

如何正确地将一个时区转换为另一个时区(包括毫秒表示)?

编辑

我需要日期/毫秒……这与正确显示时间无关……

编辑 2

现在,在评论和答案的帮助下,我尝试了以下操作:

    DateTimeZone tz = DateTimeZone.getDefault();
    DateTime nowLocal = new DateTime();
    LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
    DateTime nowUTC2 = nowLocal.withZone(DateTimeZone.UTC);

    Date dLocal = nowLocal.toDate();
    Date dUTC = nowUTC.toDate();
    Date dUTC2 = nowUTC2.toDate();

    L.d(Temp.class, "------------------------");
    L.d(Temp.class, "tz    : " + tz.toString());
    L.d(Temp.class, "local : " + nowLocal +     " | " + dLocal.toString());
    L.d(Temp.class, "utc   : " + nowUTC +       " | " + dUTC.toString()); // <= WORKING SOLUTION
    L.d(Temp.class, "utc2  : " + nowUTC2 +      " | " + dUTC2.toString());

输出

tz    : Europe/Belgrade
local : 2015-01-02T15:31:38.241+01:00 | Fri Jan 02 15:31:38 MEZ 2015
utc   : 2015-01-02T14:31:38.241 | Fri Jan 02 14:31:38 MEZ 2015
utc2  : 2015-01-02T14:31:38.241Z | Fri Jan 02 15:31:38 MEZ 2015

我想要的是,本地日期显示 15 点,UTC 日期显示 14 点... 目前,这似乎可行...

----- EDIT3 - 最终解决方案-----

希望这是一个很好的解决方案...我认为,我尊重我得到的所有提示...

    DateTimeZone tz = DateTimeZone.getDefault();
    DateTime nowUTC = new DateTime(DateTimeZone.UTC);
    DateTime nowLocal = nowUTC.withZone(tz);

    // This will generate DIFFERENT Dates!!! As I want it!
    Date dLocal = nowLocal.toLocalDateTime().toDate();
    Date dUTC = nowUTC.toLocalDateTime().toDate();

    L.d("tz    : " + tz.toString());
    L.d("local : " + nowLocal +     " | " + dLocal.toString());
    L.d("utc   : " + nowUTC +       " | " + dUTC.toString());

输出:

tz    : Europe/Belgrade
local : 2015-01-03T21:15:35.170+01:00 | Sat Jan 03 21:15:35 MEZ 2015
utc   : 2015-01-03T20:15:35.170Z | Sat Jan 03 20:15:35 MEZ 2015

【问题讨论】:

标签: java jodatime


【解决方案1】:

你让它变得比你需要的复杂得多:

DateTime dt = new DateTime(DateTimeZone.UTC);

根本不需要转换。如果您发现确实需要转换,可以使用withZone。但是,我建议您避免通过LocalDateTime,因为这样您可能会由于时区转换而丢失信息(两个不同的时刻可以在同一时区具有相同的本地时间,因为时钟返回并重复当地时间。

说了这么多,为了可测试性,我个人喜欢使用Clock 接口,它允许我获取当前时间(例如Instant)。然后,您可以在生产中运行时使用依赖注入注入真实的系统时钟,并使用预设时间的假时钟进行测试。 Java 8 的 java.time 包内置了这个想法,顺便说一句。

【讨论】:

  • @prom85:不清楚您为什么要转换为Date,您的实际输出是什么,或者您的预期输出是什么。请记住,Date.toString() always 使用系统默认时区...您可能只是被那里的输出弄糊涂了。我建议尽量避免使用Date。
  • @prom85:你不想要withZoneRetainFields,但同样,听起来问题出在其他地方——我怀疑这与你如何将值保存到数据库有关。如果不了解数据库的任何信息(这是第一次提到它),很难为您提供帮助。
  • @prom85:这真的确实很重要,因为你的“测试”被破坏了,并且可能与你真正想要做的事情完全无关。在特定时区没有java.util.Date 这样的概念。 Date 类only 存储一个时间点。它不知道您对哪个时区感兴趣。“java.util.Date 表示您当地时区当前时间的对象”的概念是不合理的,就像说“我想要一个 @987654335 @ 以十六进制存储我的年龄” - int 没有格式,就像 Date 没有时区一样。
  • @prom85:我认为您没有正确阅读我的评论。将java.util.Date 从一个时区转换到另一个时区的想法是荒谬的,因为java.util.Date 没有 时区。目前尚不清楚用户上传数据的来源,但您确实需要先了解Date 没有时区的核心观点。
  • @prom85:正如我之前所说,您不可能期望得到代表同一时间点的Date 值的不同结果。您还在没有指定时区的情况下调用LocalDateTime.toDate - 那不是一个好主意。但仍不清楚为什么您的示例代码都没有使用我的答案中的代码,即new DateTime(DateTimeZone.UTC)。老实说,目前还不清楚你为什么关心系统本地时区。恐怕我今天无法提供更多帮助,但我认为您确实需要仔细考虑您的要求。
【解决方案2】:

您还可以使用静态方法now,使其更具可读性

DateTime.now(DateTimeZone.UTC)

【讨论】:

  • 哇!简洁明了。
【解决方案3】:

使用这个

DateTime.now().withZone(DateTimeZone.UTC)

如果你想格式化,你可以使用

DateTime.now().withZone(DateTimeZone.UTC).toString("yyyyMMddHHmmss")

【讨论】:

    【解决方案4】:

    请尝试听取 Jon Skeets 的好建议和 cmets。这里有一个额外的解释。您的 edit-2 包含一个错误:

    DateTimeZone tz = DateTimeZone.getDefault();
    DateTime nowLocal = new DateTime();
    LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
    DateTime nowUTC2 = nowLocal.withZone(DateTimeZone.UTC);
    
    Date dLocal = nowLocal.toDate();
    Date dUTC = nowUTC.toDate();
    Date dUTC2 = nowUTC2.toDate();
    

    如果您在 nowUTC 类型为 LocalDateTime 的对象上调用 toDate(),那么您可以获得惊喜 - 请参阅 javadoc。 Joda-Time 声称在java.util.Date 中使用the same fields,就像在nowUTC 中一样。这是什么意思?我们来分析一下:

    nowUTC.toString() 产生 2015-01-02T14:31:38.241 即没有时区(注意最后缺少的 Z),所以它只是一个普通的本地时间戳。根据上下文,我们知道它是在 UTC 中生成的。但是,在下一步中,您使用上述方法将其转换为 java.util.Date。此方法将本地时间戳与系统时区(贝尔格莱德)相结合,保留字段,因此更改瞬间。所以你终于错误地纠正了你的瞬间。而且你的第二行是错误的。

    如果你只是想要

    UTC日期显示14点

    然后不要使用 Joda-Time 提供的可疑和误导性转换方法。改用具有“EEE MMM dd HH:mm:ss zzz yyyy”或类似模式的专用格式化程序(Joda-Time 提供 DateTimeFormatter)。在此格式化程序上设置 UTC 偏移量并打印。完毕。完全放弃java.util.Date.toString() 的任何电话。这样,您甚至根本不需要进行任何危险的转换。

    【讨论】:

      【解决方案5】:

      从这里:http://www.joda.org/joda-time/userguide.html#Changing_TimeZone

      // get current moment in default time zone
      DateTime dt = new DateTime();
      // translate to London local time
      DateTime dtLondon = dt.withZone(DateTimeZone.forID("Europe/London"));
      

      结果值 dtLondon 具有相同的绝对毫秒时间,但一组不同的字段值。

      您可以将“欧洲/伦敦”替换为您想要的时区 (UTC)。见this list of proper time zone names。

      【讨论】:

        【解决方案6】:
            SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
            // or SimpleDateFormat sdf = new SimpleDateFormat( "MM/dd/yyyy KK:mm:ss a Z" );
            sdf.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
            System.out.println( sdf.format( new Date() ) 
        
        );
        

        而不是 System.out.println(sdf.format(new Date()) 输入您的本地日期

        【讨论】:

        • 我编辑了我的问题...我需要日期/毫秒...正确显示日期是不够的...谢谢
        【解决方案7】:

        我用这个转换器解决了这个问题

        public class DateTimeConverter implements AttributeConverter<DateTime, Date> {
            @Override
            public Date convertToDatabaseColumn(DateTime attribute) {
                return attribute == null ? null
                        : new Date(attribute
                                .withZone(DateTimeZone.UTC)
                                .withZoneRetainFields(DateTimeZone.getDefault())
                                .getMillis());
            }
        
            @Override
            public DateTime convertToEntityAttribute(Date dbData) {
                return dbData == null ? null
                       : new DateTime(dbData.getTime())
                                .withZoneRetainFields(DateTimeZone.UTC)
                                .withZone(DateTimeZone.getDefault());
            }
        }
        

        日期存储为 UTC 并使用您当前的时区恢复

        【讨论】:

          猜你喜欢
          • 2011-03-20
          • 1970-01-01
          • 2011-11-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-18
          • 1970-01-01
          • 2019-07-28
          相关资源
          最近更新 更多