【问题标题】:Java: How to convert a string (HH:MM:SS) to a duration?Java:如何将字符串(HH:MM:SS)转换为持续时间?
【发布时间】:2012-01-05 15:46:17
【问题描述】:

我想将格式为 HH:MM:SS 或 MM:SS 或 SS 的字符串转换为 Duration 数据类型。

解决方案:

    private ArrayList<Duration> myCdDuration = new ArrayList<Duration>();

        private void convert(String aDuration) {

            chooseNewDuration(stringToInt(splitDuration(aDuration))); //stringToInt() returns an int[] and splitDuration() returns a String[]
        }

        private void chooseNewDuration(int[] array) {
            int elements = array.length;
            switch (elements) {
            case 1:
                myCdDuration.add(newDuration(true, 0, 0, 0, 0, 0, array[0]));
                break;
            case 2:
                myCdDuration.add(newDuration(true, 0, 0, 0, 0, array[0], array[1]));
                break;
            case 3:
                myCdDuration.add(newDuration(true, 0, 0, 0, array[0], array[1],
                        array[2]));
                break;
            }
        }

感谢您的帮助...有更简单的方法吗? -> 创建你自己的 Duration 类:

public class Duration {
        private int intSongDuration;
        private String printSongDuration;

        public String getPrintSongDuration() {
            return printSongDuration;
        }

        public void setPrintSongDuration(int songDuration) {
            printSongDuration = intToStringDuration(songDuration);
        }

        public int getIntSongDuration() {
            return intSongDuration;
        }

        public void setIntSongDuration(int songDuration) {
            intSongDuration = songDuration;
        }

        public Duration(int songDuration) {

            setIntSongDuration(songDuration);
        }

将 int 值转换为 String 用于输出/打印:

private String intToStringDuration(int aDuration) {
    String result = "";

    int hours = 0, minutes = 0, seconds = 0;

    hours = aDuration / 3600;
    minutes = (aDuration - hours * 3600) / 60;
    seconds = (aDuration - (hours * 3600 + minutes * 60));

    result = String.format("%02d:%02d:%02d", hours, minutes, seconds);
    return result;
}

【问题讨论】:

  • 您不能将字符串转换为任何其他对象,因为编程不是这样工作的。也许您想向我们展示 Duration 类的样子。也许它有一个接受 Date 对象或接受 Strings 或 ints 的构造函数?
  • 在 XML 中使用的 Duration 类...不要以其他方式使用...

标签: java string duration


【解决方案1】:

我假设您最终要达到的目标是以秒为单位计算 CD 的持续时间。

有几种方法可以做到这一点,但我认为最直接的方法是在 : 上拆分以获取小时、分钟和秒字段,然后手动计算持续时间:

String timestampStr = "14:35:06";
String[] tokens = timestampStr.split(":");
int hours = Integer.parseInt(tokens[0]);
int minutes = Integer.parseInt(tokens[1]);
int seconds = Integer.parseInt(tokens[2]);
int duration = 3600 * hours + 60 * minutes + seconds;

【讨论】:

  • 在我们知道 Duration 是什么之前回答肯定会给你错误的答案。
  • 尽管不知道 Frank 想用 javax.xml.datatype.Duration 做什么,但我认为他的最终目标从这个主题很清楚。但我确实明白你的意思,我可能是错的。 :P 我编辑了我的答案以陈述我的假设。
  • 那么现在呢?他会尝试将 int 转换为 Duration 吗?关键是要理解 Duration 数据类型,然后用它找到正确的方法来构造它——这里有一个 DataTypeFactory,如 andri 所示(对他来说是 1+)。
  • 正如亚历克斯指出的,谁知道Duration 类是否合适?弗兰克的代码中或周围没有 XML,所以看看他试图实现的更广泛的目标可能会很有用。
  • @Hovercraft Full Of Eels 他需要从字符串中解析出时间量(或者进入你的气垫船去疯人院!!;)
【解决方案2】:
  1. 您的myCdDuration 令人困惑。你想要一个 Duration 对象与字符串中指定的任何内容等效,还是要一个Duration 对象列表,其中第一个包含小时、第二个分钟等?

    李>
  2. 您不能只将String 投射到其他对象中。您应该将值解析为数字类型并使用DataTypeFactory 构造Duration 对象。

【讨论】:

  • to 1: a list...element 0 for hours etc.. 但是再看一看,只创建一个对象会更容易,因为持续时间类有 getHouts()、getMinutes( ) 和 getSeconds() 到 2:谢谢..我试试吧
  • 感谢 2. ...它工作正常,但在我的程序代码中看起来很糟糕,从 string[] 转换为 int[] 并使用 switch/case 语句创建 newDuration 因为所有这些不同的参数.
  • 您是否确定首先需要使用javax.xml.datatype.Duration 类?正如其他人所说,它旨在与 Java XML 库一起使用。看看你的另一个问题,如果你只想存储 CD 曲目的长度,我会使用一个普通的旧 int 并以秒为单位存储持续时间,就像 Mansoor 的回答一样(或者使用 joda-time.sourceforge.net 库,如果我预计我需要编写大量代码来处理时间、日期和/或持续时间)。
  • 嗯...谢谢大家。我用私有类变量 int intSongDuration 和 String printSongDuration 创建了一个类 Duration。该类还有一个方法 public String intToStringDuration(intaDuration) 将 int aDuraation 转换为 hh:mm:ss String。
【解决方案3】:

我建议不要使用javax.xml.datatype.Duration,因为它与XML Java API 相关,如果您不处理XML,使用它会令人困惑。此外,它是一个抽象类,在 Java SE 中没有非抽象记录的实现,因此您必须创建自己的非抽象实现或以某种方式获取实例(可能是使用 XML API) .

您可以使用DateCalendar 类在Java 中管理时间和日期。要将Strings 转换为Date/Calendar,请使用DateFormatSimpleDateFormat。这将让你执行你的持续时间算术,虽然这不是 100% 漂亮。

Mansoor 提供了一种手动执行操作的方法,使用字符串操作并将持续时间作为数值处理 - 如果您只执行简单的操作,这样做可能更直接。

如果您必须执行更复杂的操作,您可能需要查看http://joda-time.sourceforge.net/

【讨论】:

  • 如果是家庭作业,那么弗兰克可能不得不选择不使用 Duration。
  • @Frank 不不!!仅使用 XML 的持续时间
【解决方案4】:

我在我的 utils 类中编写了这个方法来解析各种类型的持续时间字符串。它非常灵活:

public static int getSecondsFromFormattedDuration(String duration){
        if(duration==null)
            return 0;
        try{

            Pattern patternDuration = Pattern.compile("\\d+(?::\\d+){0,2}");

            int hours = 0;
            int minutes = 0;
            int seconds = 0;
            if(patternDuration.matcher(duration).matches()){
                String[] tokens = duration.split(":");
                if(tokens.length==1){
                    seconds = Integer.parseInt(tokens[0]);
                }else if(tokens.length == 2){
                    minutes = Integer.parseInt(tokens[0]);
                    seconds = Integer.parseInt(tokens[1]);
                }else{
                    hours = Integer.parseInt(tokens[0]);
                    minutes = Integer.parseInt(tokens[1]);
                    seconds = Integer.parseInt(tokens[2]);
                }

                return 3600 * hours + 60 * minutes + seconds;
            }else
                return 0;

        }catch (NumberFormatException ignored){
            return 0;
        }

}

这就是它解析这些持续时间的方式:

"1"   -->  1
"10"  -->  10
"10:"   -->  0  (not a valid duration)
"10:07"   -->  607
"06:08"   -->  368
"7:22"   -->  442
":22"   -->  0  (not a valid duration)
"10:32:33"   -->  37953
"2:33:22"   -->  9202
"2:2:02"   -->  7322
"2:33:43:32"   -->  0  (not a valid duration)
"33ff"   -->  0  (not a valid duration)
"2d:33"   -->  0  (not a valid duration)

【讨论】:

    【解决方案5】:

    使用 Java 8 和 Java.time.Duration,如果字符串的格式为 HH:MM:SS 或 MM:SS 或 SS,您可以这样做

    Duration.ofSeconds(Arrays.stream(runtime.split(":"))
                      .mapToInt(n -> Integer.parseInt(n))
                      .reduce(0, (n, m) -> n * 60 + m));
    

    【讨论】:

    • 有趣的方法,但是像“777:888:999999”这样的值呢?他们会处理这个提案,但他们真的符合“HH:MM:SS”的格式吗?
    • 没有理由不工作,因为 777 小时 888 分钟和 999999 秒的数据是有意义的。将前一个值乘以 60 并添加当前值。因此,您最终会得到 (((0 * 60 + 777) * 60 + 888) * 60 + 999999) 的结果,并根据结果将其转换为持续时间。如果要求每个字段的长度仅为 2,您可能会添加一个处理 checkl 的 peek 或 map。
    【解决方案6】:

    tl;博士

    无需定义自己的Duration 类,Java 提供了一个。

    Duration.between (                  // Represent a span of time of hours, minutes, seconds. 
        LocalTime.MIN ,                 // 00:00:00
        LocalTime.parse ( "08:30:00" )  // Parse text as a time-of-day. 
    )                                   // Returns a `Duration` object, a span-of-time. 
    .toString()                         // Generate a `String` with text in standard ISO 8601 format. 
    

    PT8H30M

    并解析标准 ISO 8601 格式的文本。

    Duration.parse( "PT8H30M" )   // Parse standard ISO 8601 text yo get a `Duration` object. 
    


    避免HH:MM:SS 格式

    如果字符串08:30:00 是指“八个半小时”的时间跨度而不是一天中的“早上八点半”,那么请避免使用HH:MM:SS 的格式。这种格式模棱两可,似乎是一天中的时间。请改用下面讨论的标准 ISO 8601 格式。

    持续时间和时间是两个截然不同的概念。你必须清楚他们,每个人都应该在你的脑海中是不同的。使用 HH:MM:SS 的模棱两可的格式使区分变得更加困难(所以避免使用这种格式!)。

    java.time

    现代方法是使用 java.time 类。

    LocalTime

    首先将您的字符串解析为LocalTime。此类表示没有日期和时区的时间。没有时区意味着这些对象基于通用 24 小时制,而不考虑 Daylight Saving Time (DST) 等异常情况。

    我们并不真正想要LocalTime,因为您的输入字符串代表时间跨度而不是一天中的某个时间。但这只是第一步。

    LocalTime lt = LocalTime.parse ( "08:30:00" );
    

    Duration

    为了表示所需的时间跨度,我们需要 Duration 类。此类适用于未附加到时间线的时间跨度。我们可以通过转换LocalTime 来创建一个,方法是获取从时钟开始的时间量00:00:00.0LocalTime.MIN,以及我们刚刚实例化的lt

    Duration d = Duration.between ( LocalTime.MIN , lt );
    

    编辑输入字符串

    上述使用LocalTime 的方法仅在您的输入字符串表示的持续时间少于 24 小时时才有效。如果超过 24 小时,您将自己解析输入字符串。

    类似于以下代码。当然,实际的解析取决于解决特定输入字符串的歧义。 50:00 是 50 小时还是 50 分钟? (这种模糊性是尽可能避免这种令人困惑的格式并坚持使用 ISO 8601 格式的重要理由。)

    String input = "50:00";  // Or "50:00:00" (fifty hours, either way)
    
    String[] parts = input.split ( ":" );
    Duration d = Duration.ZERO;
    if ( parts.length == 3 ) {
        int hours = Integer.parseInt ( parts[ 0 ] );
        int minutes = Integer.parseInt ( parts[ 1 ] );
        int seconds = Integer.parseInt ( parts[ 2 ] );
        d = d.plusHours ( hours ).plusMinutes ( minutes ).plusSeconds ( seconds );
    } else if ( parts.length == 2 ) {
        int hours = Integer.parseInt ( parts[ 0 ] );
        int minutes = Integer.parseInt ( parts[ 1 ] );
        d = d.plusHours ( hours ).plusMinutes ( minutes );
    } else {
        System.out.println ( "ERROR - Unexpected input." );
    }
    

    ISO 8601

    我们可以通过调用Duration::toString 以标准ISO 8601 format for durations 生成一个字符串来查看结果。 java.time 类在解析/生成字符串时默认使用 ISO 8601。对于持续时间,标准格式为PnYnMnDTnHnMnS,其中P 标记开始,T 将年-月-日部分与小时-分钟-秒部分分开。因此,我们的八个半小时将显示为PT8H30M

    System.out.println("d.toString():" + d);

    d.toString(): PT8H30M

    收集Duration 对象

    您可以创建一个List 来保存Duration 类型的元素。

    List<Duration> durations = new ArrayList<>( 3 );  // Initial capacity of 3 elements.
    durations.add( d ) ;
    durations.add( Duration.between ( LocalTime.MIN , LocalTime.parse ( "03:00:00" ) ) ) ;
    durations.add( Duration.between ( LocalTime.MIN , LocalTime.parse ( "01:15:00" ) ) ) ;
    

    durations.toString(): [PT8H30M, PT3H, PT1H15M]

    请记住,您在该输出中看到的字符串(例如 PT8H30M)就是:生成字符串的输出。 Duration 类型不是简单的字符串,而是通过其toString 方法生成一个字符串对象。

    如果您坚持使用 ISO 8601 格式,则可以轻松解析和生成此类字符串。无需通过我们在此答案顶部执行的LocalTime 转换 rigamarole。

    Duration d = Duration.parse( "PT8H30M" );
    

    请参阅此示例code live in IdeOne.com


    关于java.time

    java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

    Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

    要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

    从哪里获得 java.time 类?

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

    【讨论】:

    • 那些使用 spring 的人可能还想查看DurationStyle::detectAndParse,除了 ISO-8601 之外,它还允许使用更易读的格式,例如 30ms。 (Reference,有点)
    【解决方案7】:

    示例,在 Java 7 中将当前日期时间转换为持续时间。

    DatatypeFactory.newInstance().newDuration(Calendar.getInstance().getTimeInMillis())
    

    输出 -

    P48Y5M13DT19H59M24.658S

    【讨论】:

      【解决方案8】:

      java.time.Duration

      其他几个答案已经提到,来自现代 Java 日期和时间 API 的 java.time 中的 Duration 类是要在一段时间内使用的类。有一些方法可以将你的字符串解析为Duration,老实说,还不清楚哪一个是最好的。我想介绍我的方式。

      基本

      我只从一种可能的格式开始简单,hh:mm:ss,例如 01:30:41 1 小时 30 分 41 秒。

          String durationString = "01:30:41";
          
          String iso = durationString.replaceFirst(
                  "^(\\d{2}):(\\d{2}):(\\d{2})$", "PT$1H$2M$3S");
          Duration dur = Duration.parse(iso);
          
          System.out.format("%-10s  Total %2d minutes or %4d seconds%n",
                  dur, dur.toMinutes(), dur.toSeconds());
      

      目前的输出是:

      PT1H30M41S  Total 90 minutes or 5441 seconds
      

      Duration.parse 方法需要 ISO 8601 格式。它就像PT1H30M41S 一样持续 1 小时 30 分 41 秒。所以我要做的是通过正则表达式将您的字符串转换为这种格式。我的替换字符串中的$1 等将替换为正则表达式中圆括号中的groups 匹配的内容。所以durationString.replaceFirst() 将你的字符串转换为PT01H30M41SDuration 可以解析。

      三种格式

      您要求转换 HH:MM:SS 或 MM:SS 或 SS。对上面的修改其实很简单:我们只需要对replaceFirst() 进行三次调用,而不是一次。他们中的一个将成功取代任何​​东西。其他两个将只返回未更改的字符串。

          String[] durationStrings = { "01:32:43", "26:31", "14" };
          
          for (String durationString : durationStrings) {
              String iso = durationString.replaceFirst("^(\\d{2}):(\\d{2}):(\\d{2})$", "PT$1H$2M$3S")
                      .replaceFirst("^(\\d{2}):(\\d{2})$", "PT$1M$2S")
                      .replaceFirst("^(\\d{2})$", "PT$1S");
              Duration dur = Duration.parse(iso);
              
              System.out.format("%-10s  Total %2d minutes or %4d seconds%n",
                      dur, dur.toMinutes(), dur.toSeconds());
          }
      
      PT1H32M43S  Total 92 minutes or 5563 seconds
      PT26M31S    Total 26 minutes or 1591 seconds
      PT14S       Total  0 minutes or   14 seconds
      

      Time4J 和 net.time4j.Duration

      如果您对外部依赖感到满意,Time4J 库提供了一种更优雅的方式来将您的字符串解析为持续时间对象。我们首先声明一个格式化程序:

      private static final Duration.Formatter<ClockUnit> FORMATTER 
              = Duration.formatter(ClockUnit.class, "[[hh:]mm:]ss");
      

      格式模式字符串中的方括号围绕可选部分,因此此格式器接受所有 hh:mm:ss、mm:ss 和仅 ss。

          for (String durationString : durationStrings) {
              Duration<ClockUnit> dur = FORMATTER.parse(durationString);
      
              long minutes = dur.with(ClockUnit.MINUTES.only())
                      .getPartialAmount(ClockUnit.MINUTES);
              long seconds = dur.with(ClockUnit.SECONDS.only())
                      .getPartialAmount(ClockUnit.SECONDS);
              
              System.out.format("%-10s  Total %2d minutes or %4d seconds%n",
                      dur, minutes, seconds);
          }
      

      输出和之前一样:

      PT1H32M43S  Total 92 minutes or 5563 seconds
      PT26M31S    Total 26 minutes or 1591 seconds
      PT14S       Total  0 minutes or   14 seconds
      

      链接

      【讨论】:

      • 最近几天,我看到您发布 Time4J 解决方案以及java.time 解决方案。这确实是向前迈出的一大步,因为 Time4J 在 Android 开发人员中也很受欢迎。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-02
      • 2016-07-17
      • 2016-02-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多