【问题标题】:SimpleDateFormat sometimes wrong hours formattingSimpleDateFormat 有时错误的小时格式
【发布时间】:2018-06-23 21:54:12
【问题描述】:

我想将我的时间戳转换为 XXhours:YYminutes 字符串。我的方法有时会正常工作,除非它获得更大的价值。例如,

193500000 -> 05hours:45minutes(错误,正确的是 53hours:45minutes)
60300000 -> 16 小时:45 分钟(正确)
63900000 -> 17 小时:45 分钟(正确)
108000000-> 06hours:00minutes(错误,正确的是 30hours:00minutes)
117000000 -> 08hours:30minutes(错误,正确的是 32hours:30minutes)

    SimpleDateFormat dateFormat = new SimpleDateFormat("HH'hours' mm'minutes'");
    dateFormat.setTimeZone( TimeZone.getTimeZone( "GMT"));
    String string  = dateFormat.format(totalTime);

【问题讨论】:

  • 在 Java 中日期不是小时计数器。
  • 您正在尝试使用输出日期的函数来输出持续时间。这是完全不支持的; Java就在这里,你错了。一天只有 24 小时,所以 HH 永远不会超过 24 小时。 193500000 是 1970 年的第三天,格林威治标准时间凌晨 05:45。
  • 我现在明白了:/我没想到
  • 顺便说一句,即使对于正确/受支持的用途,我建议您不要使用早已过时且臭名昭著的麻烦 SimpleDateFormat 类。 java.time, the modern Java date and time API, 使用起来更好。此外还包括一个专门为您的目的而制作的 Duration 类(尽管不幸的是它不适合格式化)。
  • Stack Overflow 上已经有很多答案可能会有所帮助,例如this one

标签: java simpledateformat duration milliseconds gmt


【解决方案1】:

再仔细阅读一遍:https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

HH 是 一天 中的小时数,从不超过 24 :-)

你想要的大概是这样的:

    int msecPerHour = 3600*1000;
    int hours = totalTime/msecPerHour;
    int msecPerMinute = 60*1000;
    int minutes = totalTime/msecPerMinute - hours*60;
    String str = "" + hours + " hours " + minutes + " minutes";

【讨论】:

    【解决方案2】:

    不幸的是,SimpleDateFormat 是不可能的。 “HH”表示一天中的小时。如果您的日期超过 24 小时,则结果将模 24。

    我建议您使用新的时间 API 编写自定义代码。

    示例如下:

        Duration duration = Duration.ofMillis(193500000);
    
        long minutes = duration.toMinutes() % 60;
        long hours = duration.toHours();
    
        System.out.println("" + hours + "hours:"+minutes+"minutes");
    

    【讨论】:

    【解决方案3】:

    The answer by talex 是正确的,您应该为此使用Duration。在 Java 9 格式中,Duration 变得更容易编写和阅读:

    public static String formatDuration(long totalTimeMillis) {
        Duration totalDuration = Duration.ofMillis(totalTimeMillis);
        return String.format(Locale.ENGLISH,
                "%02d hours %02d minutes",
                totalDuration.toHours(),
                totalDuration.toMinutesPart());
    }
    

    我们不再需要模运算(或类似运算)来查找分钟。为了证明我使用问题中的时间值调用了上述方法:

        System.out.println(formatDuration(60300000));
        System.out.println(formatDuration(63900000));
        System.out.println(formatDuration(108000000));
        System.out.println(formatDuration(117000000));
        System.out.println(formatDuration(193500000));
    

    它会打印您要求的结果:

    16 hours 45 minutes
    17 hours 45 minutes
    30 hours 00 minutes
    32 hours 30 minutes
    53 hours 45 minutes
    

    我在数字和单位之间放了一个空格,我觉得这样更可读,如果你不想要它可以删除它。

    格式字符串中的%02d 说明符可确保您获得两个数字,如问题中所必需的前导零:formatDuration(14700000),例如产生04 hours 05 minutes

    SimpleDateFormat 用于格式化日期和/或一天中的时间,而不是持续时间或经过的时间。我说“was”是因为那个类现在已经过时了,而且它也是出了名的麻烦,我建议你永远不要再使用它。要格式化日期或时间,请使用来自java.timeDateTimeFormatter

    【讨论】:

      【解决方案4】:

      193500000 -> 05hours:45minutes(错误,正确的是 53hours:45minutes)
      那是因为 53 小时 = 2 天 5 小时

      60300000 -> 16 小时:45 分钟(正确)
      63900000 -> 17 小时:45 分钟(正确)

      108000000-> 06hours:00minutes(错误,正确的是 30hours:00minutes)
      那是因为 30 小时 = 1 天 6 小时

      117000000 -> 08hours:30minutes(错误,正确的是 32hours:30minutes)
      那是因为 32 小时 = 1 天 8 小时

      如果你只想从毫秒计算小时数:

      193500000/(1000*60*60)   = number of hours  
      (193500000/(1000*60))%60 = number of remaining minutes 
      

      【讨论】:

      • 您说得对,先生,我没有这样想过。谢谢!
      • java.time 类是海边的,让你的代码更加自我记录。
      【解决方案5】:

      SimpleDateFormat 是这个要求的错误类

      您的要求是计算持续时间而不是日期时间。 SimpleDateFormatjava.time.format.DateTimeFormatter(现代日期时间 API 的一部分)应用于表示日期/时间/日期时间,即表示时间点而不是时间段/持续时间的东西。要记住这一点的经验法则是:

      1. 使用SimpleDateFormatjava.time.format.DateTimeFormatter 表示您在英语语法时态中使用since 引用的内容。
      2. 使用Period and Duration 表示您在英语语法时态中使用for 引用的内容。

      查看The Difference between Since and For – English grammar

      为了从毫秒获取持续时间,您可以使用java.time.Duration,它以ISO-8601 standards 为模型,并作为JSR-310 implementation 的一部分引入Java-8Java-9 引入了一些更方便的方法。

      演示:

      import java.time.Duration;
      
      public class Main {
          public static void main(String[] args) {
              Duration duration = Duration.ofMillis(193500000);
              // Default format
              System.out.println(duration);
      
              // Custom format
              // ####################################Java-8####################################
              String formattedElapsedTime = String.format("%02d hours %02d minutes", duration.toHours(),
                      duration.toMinutes() % 60);
              System.out.println(formattedElapsedTime);
              // ##############################################################################
      
              // ####################################Java-9####################################
              formattedElapsedTime = String.format("%02d hours %02d minutes", duration.toHours(), duration.toMinutesPart());
              System.out.println(formattedElapsedTime);
              // ##############################################################################
          }
      }
      

      输出:

      PT53H45M
      53 hours 45 minutes
      53 hours 45 minutes
      

      Trail: Date Time 了解现代日期时间 API。

      【讨论】:

        【解决方案6】:

        您似乎正在尝试转换持续时间,而不是日期时间。 SimpleDateFormat 用于将日期时间格式化为不同语言环境的不同格式。

        您可能正在寻找类似的东西来在持续时间之间进行转换:

        String.format("%d hours, %d minutes", 
            TimeUnit.MILLISECONDS.toHours(millis),
            TimeUnit.MILLISECONDS.toMinutes(millis) - 
            TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis))
        );
        

        【讨论】:

          猜你喜欢
          • 2012-12-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-08
          • 2020-07-09
          • 2012-05-24
          • 1970-01-01
          • 2018-11-15
          相关资源
          最近更新 更多