【问题标题】:Java returns wrong Time object when comparing two TimesJava 在比较两个时间时返回错误的时间对象
【发布时间】:2016-02-01 23:06:26
【问题描述】:

我今天在用java创建一个杰作,我需要计算两次之间的差异。

所以我使用Time.getTime() 来获取时间的长值并减去它们以获得我想要的......

这是我的测试代码:

public static void main(String[] args) {    
    Time time = new Time(00,00,00);
    Time time2 = new Time(02,00,00);
    long longTime = (time2.getTime() - time.getTime());
    Time finalTime = new Time(longTime);
    System.out.println(finalTime.toString());
}

现在显然打印出来的字符串必须是 02:00:00

但我总是得到 04:00:00

我尝试了很多时间,我总是把时间增加两个小时,我不知道为什么。

我什至试图减去 00:00:00 和 00:00:00

而不是得到 00:00:00

我得到了 02:00:00

那么,对我有什么帮助吗???

【问题讨论】:

  • 我感觉这可能与您的语言环境/时区有关。您认为new Time(0) 应该为您返回什么?
  • 不是为了破坏你所做的事情,但你为什么使用 java.sql.Time 而不是 java.util.Date?你能切换到日期吗? @Pshemo,它与语言环境和时区有关。我运行他的代码并得到 19:00:00
  • @jheimbouch 我使用了 Date 并尝试了它.. 仍然增加了几个小时
  • Date 的许多方法已弃用。我将使用 GregorianCalendar 编写一个示例。给我一些。

标签: java date time subtraction


【解决方案1】:

问题在于,在您打印时间时,它正在转换为您的时区。基本上时区仅用于演示,而不是存储日期的方式。你必须显示你的格林威治标准时间,然后它会给你你想要的。像这样:

Time time = new Time(00,00,00);
Time time2 = new Time(02,00,00);
long longTime = (time2.getTime() - time.getTime());
Time finalTime = new Time(longTime);
System.out.println(finalTime.toString());
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
//correct one
System.out.println(sdf.format(finalTime));

另外,我认为您正在使用 java.sql.Time 类,除非您正在执行 sql,否则我猜这是使用错误的类。 Date 类有你需要的一切,Calendar 类也是如此。还有一些我没用过但看起来很有趣的新 java 时间类 https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html

【讨论】:

  • 当看到 Time 类来自 sql 包时,我感到很奇怪......因为 Time 类是从 DATE 类继承的......并且它具有相同的方法,除了它只处理时间而没有日期..
  • 是的,java.time 框架确实是一个巨大的改进。应避免使用旧的日期时间类。见Tutorial
【解决方案2】:

时间构造函数 new Time(long) 使用您的时区。

所以您的longTime 是 60*60*2*1000=7200000,如您所愿。

new Time(7200000) 将采用 1. January 1970 00:00:00 UTC/GMT + 7200000 作为新日期,因此它会按您的时区移动。 对我来说,您的代码打印:03:00:00。 new Time(int, int, int) 已弃用,不应使用。

因此,如果可能的话,我建议不要使用旧的日期和时间,而是使用 jodatime 或 java8:Do we have a TimeSpan sort of class in Java

【讨论】:

    【解决方案3】:

    这是一种使用 GregorianCalendar 来做你想做的事情的方法:

    Calendar time = new GregorianCalendar();
    Calendar time2 = new GregorianCalendar();
    time2.add(GregorianCalendar.HOUR, 2);
    
    System.out.println(time2.getTimeInMillis() - time.getTimeInMillis());
    

    【讨论】:

      【解决方案4】:

      这是交易...

      首先,如果可能的话,我建议不要使用 Time 类,因为它的方法大多已被弃用。

      尝试使用 Date 类或 Duration 和 Instant https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html

      如果你现在必须坚持这个课程,这里就是诀窍。

      构造函数new Time(long) 考虑了时区偏移...

      因此,如果您处于 +02 时区...您的时间对象将在 120 分钟内增加。

      要解决这个问题,您可以使用Time.getTimezoneOffset()

      此方法将返回一个整数,其中包含您所在时区的分钟数

      我编辑了我的代码,现在它可以正常工作了:

      public static void main(String[] args) {
      
      
          Time time = new Time(00,00,00);
          Time time2 = new Time(02,00,00);
      
          long longTime = (time2.getTime() - time.getTime());
      
          Time finalTime = new Time(longTime);
      
          int timeOffset = time.getTimezoneOffset();
          finalTime.setMinutes(finalTime.getMinutes()+timeOffset);
      
          System.out.println(finalTime.toString());   
      
          }
      

      【讨论】:

        【解决方案5】:

        八进制数

        您在 Java 中的文字数字上使用了前导零。这意味着octal number(以 8 为基数)而不是十进制数(以 10 为基数)。

        您应该使用0 代替00,并使用2 代替02

        这个特定示例中的核心问题不太可能是八进制零和两个在十进制中具有相同的值。

        在我看来,这个问题没有实际意义。有更好的方法来实现您的目标;继续阅读。

        java.time

        问题和其他答案使用与最早版本的 Java 捆绑在一起的旧的过时日期时间类。那些旧的类已被证明是相当麻烦的、有缺陷的和设计不佳的。它们在 Java 8 和后来的 java.time 框架中被取代。见Tutorial

        新类包括LocalTime,用于表示没有任何日期或任何时区的时间值。

        优先使用LocalTime 类而不是java.sql.Time。 java.sql.* 类仅用于将数据传入和传出数据库,而不用于业务逻辑。特别是,java.sql.Time 类假装只有一个时间,但实际上是 java.util.Date 的子类(一个被黑的类设计),所以在内部它确实有一个日期和时区(UTC 和 另一个隐藏在源代码中但出于某些目的而被忽略的时区)。使困惑?正如我所说,旧的日期时间类是一团糟,应该避免;仅在绝对必要的情况下使用并尽可能简短。

        传输后立即将 java.sql 类型转换为 java.time 类型。 java.sql.Time 类提供了toLocalTime 方法,方便转换。

        LocalTime localTime = myJavaSqlTime.toLocalTime();
        

        已过

        似乎您的问题是关于确定一对时间之间经过的时间。

        请记住在没有日期的情况下确定经过时间的问题。我们必须假设一般的 24 小时全天,同时忽略夏令时 (DST) 或现实世界中发生的其他异常情况。我们必须假设这些发生在同一天,或者延续到下一个 24 小时制。所以一般来说,你最好将时间轴上的实际时刻表示为InstantZonedDateTimeOffsetDateTime

        java.time 框架提供了Duration 类来将时间跨度表示为整秒加上nanoseconds 中的几分之一秒。

        假设您已检索 java.sql.Time 对象并将它们转换为 java.time.LocalTime 对象,让我们模拟从数据库中获取一对值。

        LocalTime start = LocalTime.of ( 0 , 0 , 0 ); // First moment of the day.
        LocalTime stop = LocalTime.of ( 2 , 0 , 0 ); // 2 AM.
        

        将时间跨度计算为小时数、分钟数和秒数。

            Duration duration = Duration.between ( start , stop );
        

        转储到控制台。

            System.out.println ( "start: " + start + " | stop: " + stop + " | duration: " + duration );
        

        注意对LocalTime::toString 的隐式调用的输出如何使用PnYnMnDTnHnMnS 的标准ISO 8601 格式。在我们的例子中,PT2H 表示“两个小时”。 java.time 类可以解析和生成 ISO 8601 格式。这种标准格式比使用无法与时间区分的模棱两可的02:00:00 更明智。

        开始:00:00 |停止:02:00 |持续时间:PT2H

        如果你想要数字,你可能会得到持续时间的总秒数。请记住,持续时间可能包括纳秒的小数秒,而整秒会被忽略。

        long seconds = duration.get ( ChronoUnit.SECONDS );  // 7,200 seconds in 2 hours.
        

        或调用to 方法,例如toHourstoMinutes 以获取作为这些单位总数的持续时间。

        如果您打算将这些通用时间值应用于特定日期以获得时间线上的实际时刻,请搜索 Stack Overflow,因为这已涵盖。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-09-21
          • 1970-01-01
          • 2019-08-29
          • 1970-01-01
          • 2014-10-31
          • 2012-02-04
          • 2017-09-05
          • 1970-01-01
          相关资源
          最近更新 更多