3

I have an input string of 'HH:mm' format where time separator is according to locale settings (e.g. '10:45' for US or '10.45' for Italy). I need to convert it into amount of minutes.

Here is what I came up with:

String timeSeparator = getTimeSeparator(locale);
String[] duration = durationString.split(Pattern.quote(timeSeparator));
int minutes = Integer.valueOf(duration[0])*60 + Integer.valueOf(duration[1]);

getTimeSeparator method taken from https://stackoverflow.com/a/7612009/7753225

Is there any simpler way? For example using `java.time'.

Community
  • 1
  • 1
Lega
  • 88
  • 8
  • you can remove the Integer.valueOf() as you are not even using an Integer, (and even then, it will be autoboxed). I think JodaTime had this option though. To get the number of minutes/seconds/whatever from a datetime – Wietlol Mar 23 '17 at 18:19
  • 3
    Why not just ignore the separator? `int minutes = Integer.parseInt(durationString.substring(0, 2)) * 60 + Integer.parseInt(durationString.substring(3))` – Andreas Mar 23 '17 at 18:37

5 Answers5

2

tl;dr

Duration.parse( 
    "PT" + 
    "10:45".replace( ":" , "M" )
           .replace( "-" , "M" )
           .replace( "." , "M" )
           .replace( "," , "M" )
    + "S" 
).toMinutes()

"10:45" → PT10M45S → 10

ISO 8601 format

The ISO 8601 standard defines a format for such spans of time not attached to the time line: PnYnMnDTnHnMnS

The P marks the beginning. The T separates any years-months-days from the hours-minutes-seconds. So an hour and a half is PT1H30M. Your example of ten minutes and forty-five seconds is PT10M45S.

Perform simple string manipulations to convert your input to this format.

String input = "10:45" ;
String inputStandardized = "PT" + 
    input.replace( ":" , "M" )
         .replace( "-" , "M" )
         .replace( "." , "M" )
         .replace( "," , "M" )
         + "S" ;

PT10M45S

Duration

Parse as a Duration. The java.time classes use ISO 8601 formats by default when parsing and generating strings. So no need to specify a formatting pattern.

Duration duration = Duration.parse( inputStandardized );

duration.toString(): PT10M45S

You can use the Duration object to do date-time math, passing to plus and minus. So you may not need the number of minutes as an integer number. But you can ask for total number of minutes in the duration.

long minutes = duration.toMinutes();

10

See this code run live at IdeOne.com.

Tip: Using a clock-time format for a span of time is asking for trouble. The ambiguity leads to confusion and errors. I suggest using the standard ISO 8601 formats for durations as they are designed to be unambiguous, easy to read, and easy to parse.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1

In Java 8 you could use DateTimeFormatter.ofLocalizedTime to obtain a locale-specific date-time formatter. Then you could use it to parse the string into a LocalTime and extract the minute field.

public static int getMinute(String timeString, Locale locale) {
  DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
                                                 .withLocale(locale);
  LocalTime time = LocalTime.parse(timeString, formatter);
  return time.getHour()*60 + time.getMinute();
}

Example:

System.out.println(getMinute("10.47", new Locale("fi")));   // 647
System.out.println(getMinute("11:23", Locale.ROOT));        // 683

If you don't care about the time separator, we could use a fixed pattern instead.

public static int getMinute(String timeString, Locale locale) {
  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH[:][.]mm", locale);
  LocalTime time = LocalTime.parse(timeString, formatter);
  return time.getHour()*60 + time.getMinute();
}

(The […] means optional, so it will match HH:mm, HH.mm, HHmm and HH:.mm)

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • There will be DateTimeParseException if locale is US, because timeString is in 'HH:mm" format and not 'HH:mm aa' – Lega Mar 23 '17 at 18:54
  • 1
    @Lega Well that means `HH:mm` is not the expected locale format for US. See update for an alternative. – kennytm Mar 23 '17 at 19:01
  • `return time.getMinute();` will return only minute part of LocalTime, this should be rather `return time.getHour() * 60 + time.getMinute();` to return minutes from midnight – Tomasz Jagiełło Mar 23 '17 at 19:39
1

Note very elegant, but it would do the job

String pattern = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
    .withLocale(locale).format(LocalTime.MIN)
    .replaceFirst("\\d*", "H").replaceFirst("\\d.*", "mm");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern, locale);
int minutes = formatter.parse(string).get(ChronoField.MINUTE_OF_DAY);
Holger
  • 285,553
  • 42
  • 434
  • 765
0

You can use getLocalizedDateTimePattern method to get a pattern with which to initialise a DateTimeFormatter, to parse time with given locale. The first null is for the date that you don't need in your case.

String timePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
            null, FormatStyle.SHORT, IsoChronology.INSTANCE, locale);

You then use it to create a formatter (note that you have to specify locale again):

DateTimeFormatter dtf = DateTimeFormatter.ofPattern(timePattern, locale);

If instead of the SHORT time format for the locale you expect "HHcmm" where 'c' is a non numeric char that is the time separator for that locale, then either:

  1. extract numbers from text

    String[] duration = durationString.split("\\D");
    int minutes = parseInt(duration[0])*60 + parseInt(duration[1]);
    
  2. make a DateTimeFormatter with the time separator

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern(
            String.format("HH%smm", timeSeparator), locale);
    LocalTime time = LocalTime.parse(text, dtf);
    int minutes = time.toSecondOfDay() / 60;
    

    or if you must

    int minutes = ChronoUnit.MINUTES.between(LocalTime.MIN, time);
    
Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
  • Here also will be DateTimeParseException if locale is US, because input is in 'HH:mm" format and not 'HH:mm aa' – Lega Mar 23 '17 at 20:09
0

First parse the time to a LocalTime instance, afterwards calculate the difference to the start of the day using Duration:

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendLocalized(null, FormatStyle.SHORT)
            .toFormatter(Locale.ITALY);
    LocalTime time = LocalTime.from(formatter.parse("10.45"));
    long minutes = Duration.between(LocalTime.MIN, time).toMinutes();

above results to 645

Arne Burmeister
  • 20,046
  • 8
  • 53
  • 94
  • Here also will be DateTimeParseException if locale is US, because input is in 'HH:mm" format and not 'HH:mm aa' – Lega Mar 23 '17 at 18:58