-1

I was wondering if there's a library to convert a string time input to milliseconds. I have an idea of how to make it using a for loop, but I don't think that's the best solution.

Example:

input: 10h 25m 12s
output 37512000 // ms

There's a library for that?

My input is a string like "2938s 2h 92m" and it can be on any order, so I can't use a pattern do format it.

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
  • 1
    See this https://stackoverflow.com/questions/26637168/how-to-convert-a-date-to-milliseconds – avocadoLambda May 10 '20 at 19:07
  • 2
    You should look into `java.time.Duration`. – MC Emperor May 10 '20 at 19:08
  • 2
    @Peter That doesn't work. My input is a string like "2938s 2h 92m" and it can be on any order, so I can't use a pattern do format it. –  May 10 '20 at 19:12
  • Library requests are off-topic, sorry – Michael May 10 '20 at 19:18
  • @dawis11 Assuming that `10h 25m 12s` is not the time passed since the Unix epoch, your link is leading in the wrong direction. Also the accepted answer there is using the notoriously troublesome and long outdated `SimpleDateFormat` class. No one should want to do that no matter the purpose. – Ole V.V. May 10 '20 at 21:17

5 Answers5

2

java.time.Duration

public static Duration parseDurationString(String durationString) {
    String[] components = durationString.split("\\s+");
    Duration result = Duration.ZERO;
    for (String component : components) {
        result = result.plus(Duration.parse("PT" + component));
    }
    return result;
}

I am assuming that your string represent a duration, an amount of time. Not a time of day, so LocalTime used in a couple of the answers is the wrong class to use. Represent it in a Duration object. Also not as a count of milliseconds since numbers like 37512000 are hard to read and make sense of.

Use the method above like this:

    System.out.println(parseDurationString("10h 25m 12s"));
    System.out.println(parseDurationString("2938s 2h 92m"));

Output:

PT10H25M12S
PT4H20M58S

It may take a bit of getting accustomed before it’s very much easier to read than the millisecond value, but you’ll get the hang of it. The latter, for example, you may read as a period of time of 4 hours 20 minutes 58 seconds.

The format is ISO 8601, the international standard. This is also the only format that Duration.parse() accepts. Fortunately it is very easy to produce it from each component of your input string, we just prepend the PT. After having split the string at whitespace, that is.

You may think twice before allowing your user to input the amount of time as 2938s 2h 92m, though. It could get confusing for himself or herself. A not so loose format may be more manageable. Make your own experiments with your own users if you can get an opportunity.

If you need the duration in milliseconds for an API that doesn’t accept a Duration, you need to convert, of course. Fortunately it’s easy.

    System.out.println(parseDurationString("10h 25m 12s").toMillis());

It yields what you said you wanted:

37512000

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • So much to learn about. This is an excellent answer! The OP should unaccept mine and accept this. – WJS May 11 '20 at 12:16
1

Try it like this: The quoted fields like 'h' cause the parser to ignore them

String t = "10h 25m 12s";
LocalTime time = LocalTime.parse(t, DateTimeFormatter.ofPattern("HH'h 'mm'm 'ss's'"));
int milli = time.get(ChronoField.MILLI_OF_DAY);


System.out.println(milli);

Prints

37512000

More information from java.time

If you want positional independent input you can do it like this.

The tests

String[] tests =
        { "10h 25m 12s", "25m 10h 12s", "12s 25m 10h" };

Using the method

for (String timeString : tests) {
   int millis = toMillis(timeString);
   System.out.println(millis);
}

Output

37512000
37512000
37512000

The method declaration


public static int toMillis(String timeString) {
    String regex = "(\\d+)([msh])";
    Pattern p = Pattern.compile(regex);

    Matcher m = p.matcher(timeString);
    int millis = 0;
    while (m.find()) {
        char c = m.group(2).charAt(0);
        int v = Integer.parseInt(m.group(1));
        millis += c == 'h' ? v * 3600_000 :
                c == 'm' ? v * 60_000 : v * 1000;
    }
    return millis;
}
WJS
  • 36,363
  • 4
  • 24
  • 39
1

Just another way to accomplish this task utilizing the TimeUnit Enum which is part of the java.util.concurrent package:

String input = "2d 10h 25m 12s 1200n";
// Split the above string but keep the delimiters.
String[] inputParts = input.toLowerCase().split("(?<=[dhmns])");

long totalMilliseconds = 0L;
for (String str : inputParts) {
    str = str.replaceAll("\\s+", "");
    String val = str.substring(0, str.length() - 1);
    String timeIncrement = str.substring(str.length() - 1);
    if (val.matches("\\d+")) {
        switch (timeIncrement) {
            case "d":
                totalMilliseconds += TimeUnit.DAYS.toMillis(Integer.parseInt(val));
                break;
            case "h":
                totalMilliseconds += TimeUnit.HOURS.toMillis(Integer.parseInt(val));
                break;
            case "m":
                totalMilliseconds += TimeUnit.MINUTES.toMillis(Integer.parseInt(val));
                break;
            case "n":
                totalMilliseconds += TimeUnit.NANOSECONDS.toMillis(Integer.parseInt(val));
                break;
            case "s":
                totalMilliseconds += TimeUnit.SECONDS.toMillis(Integer.parseInt(val));
                break;
        }
    }
}
System.out.println(input + " equals: " + totalMilliseconds + " Milliseconds");
DevilsHnd - 退職した
  • 8,739
  • 2
  • 19
  • 22
1

Another regexp-based solution:

static Pattern p = Pattern.compile("(?<hours>\\d+h)|(?<minutes>\\d+m)|(?<seconds>\\d+s)");

public static int getMillis(String s) {
    Matcher m = p.matcher(s);
    int total = 0;
    while (m.find()) {
        total += getNumber(m, "hours")   * 3600_000;
        total += getNumber(m, "minutes") *   60_000;
        total += getNumber(m, "seconds") *    1_000;
    }
    return total;
}

private static int getNumber(Matcher m, String groupName) {
    String value = m.group(groupName);
    if (null != value) {
        return Integer.parseInt(value.substring(0, value.length() - 1));
    }
    return 0;
}

// test
String[] ss = {"10h 25m 12s", "10m 15s", "40s 2h"};
for (String s : ss) {
    System.out.println(s + " -> " + getMillis(s));
}
// output
10h 25m 12s -> 37512000
10m 15s -> 615000
40s 2h -> 7240000
Nowhere Man
  • 19,170
  • 9
  • 17
  • 42
0

How about keeping it simple as you have a very custom requirement and your input format is not going to be same (going by your comment)

public static void main(String[] args) {

    String dateStr = " 25m 12s 10h";
    LocalTime time = LocalTime.of(getComponent(dateStr, 'h'),
            getComponent(dateStr, 'm'),
            getComponent(dateStr, 's'));
    System.out.println(time.toNanoOfDay()/1000);
}

private static int getComponent(String str, char componentIndicator) {
    String upTo = str.substring(0, str.indexOf(componentIndicator));
    return Integer.parseInt((upTo.contains(" ") ? upTo.substring(upTo.lastIndexOf(' '), str.indexOf(componentIndicator)) :
            upTo.substring(0, str.indexOf(componentIndicator))).trim());
}
A G
  • 297
  • 1
  • 7