2

I have a problem with time format.Some time I have values in hh:mm:ss and some times in mm:ss format.

My code looks like:

SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String time = "01:48:00"
Date remainedTimeDate = sdf.parse(time);

It works, when I got format hh:mm:ss but when I have time in format mm:ss I got an error like, value can not be parsed. Is it possible to dynamically change date format?

Kamil
  • 77
  • 6
  • 1
    You could just do a check on the length of the date/time String your are parsing (or the number of times ":" appears) and then make your decision what pattern to use for parsing based on that. – OH GOD SPIDERS Apr 22 '21 at 11:08
  • This is the solution, but perhaps JAVA has some mechanism to doing this automatically. – Kamil Apr 22 '21 at 11:17
  • Not built-in, no. – Andreas Apr 22 '21 at 11:36
  • 2
    I recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. If `01:48:30` is an amount of time, use `Duration`, otheriwise use `LocalTime`. Both are from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Apr 22 '21 at 11:42

3 Answers3

3

There is no in-built feature in the date-time API to do so. Moreover, the legacy date-time API (java.util date-time types and their formatting API, SimpleDateFormat) are outdated and error-prone. It is recommended to stop using them completely and switch to java.time, the modern date-time API* .

You can match the string with the regex pattern, \d{1,2}:\d{1,2} which means one or two digits separated by a colon. If the match is successful, prepend 00: to the string to convert it into HH:mm:ss format.

Demo:

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Optional;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] arg) {
        // Test
        Stream.of(
                    "01:48:00", 
                    "48:00"
        ).forEach(s -> parseToTime(s).ifPresent(System.out::println));
    }

    static Optional<LocalTime> parseToTime(String s) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("H:m:s");
        if (s.matches("\\d{1,2}:\\d{1,2}")) {
            s = "00:" + s;
        }
        LocalTime time = null;
        try {
            time = LocalTime.parse(s, dtf);
        } catch (DateTimeParseException e) {
            System.out.println(s + " could not be parsed into time.");
        }
        return Optional.ofNullable(time);
    }
}

Output:

01:48
00:48

Learn more about the modern date-time API from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
3

java.time.Duration

Assuming that your string denotes an amount of time (for example, a duration), the right class to use for it in Java is Duration from java.time, the modern Java date and time API. Unfortunately Duration cannot parse your strings out of the box. It has a parse method that only accepts ISO 8601 format. ISO 8601 format for a duration goes like for example PT1H48M30S. It looks unusual at first, but is straightforward to read when you know how. Read the example just given as a period of time of 1 hour 48 minutes 30 seconds. So to parse your strings in hh:mm:ss and mm:ss format I first convert them to ISO 8601 using a couple of regular expressions.

    // Strings can be hh:mm:ss or just mm:ss
    String[] examples = { "01:48:30", "26:57" };
    for (String example : examples) {
        // First try to replace form with two colons, then form with one colon.
        // Exactly one of them should succeed.
        String isoString = example.replaceFirst("^(\\d+):(\\d+):(\\d+)$", "PT$1H$2M$3S")
                .replaceFirst("^(\\d+):(\\d+)$", "PT$1M$2S");
        Duration dur = Duration.parse(isoString);
        System.out.format("%8s -> %-10s -> %7d milliseconds%n", example, dur, dur.toMillis());
    }

In addition my code also shows how to convert each duration to milliseconds. Output is:

01:48:30 -> PT1H48M30S -> 6510000 milliseconds
   26:57 -> PT26M57S   -> 1617000 milliseconds

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Many thanks. I didn't know, that SimpleDateFormat is long time outdated. It works for my solution too. But your is much easier to implement and it works. – Kamil Apr 23 '21 at 06:36
0

Yeah you can do that. Based on an If Condition like Say, If the Hour and Min are in Smaller Case, you can change the constructor. But Please know that simple date format is not thread safe. Either make method as synchronized or lock the Simple Date Format object.

  • 2
    Or, better yet, stop using these terrible classes that were years ago supplanted by the modern *java.time* classes defined in JSR 310. – Basil Bourque Apr 22 '21 at 16:22
  • @basil if you accept my answer can I have your upvote?? –  Apr 23 '21 at 07:49
  • 1
    You’ve missed my point. No one should be using the `SimpleDateFormst` class in 2021. That terrible class was supplanted years ago by `java.time.DateTimeFormatter` defined in JSR 310. The *java.time* classes use [immutable objects](https://en.m.wikipedia.org/wiki/Immutable_object), and are therefore [thread-safe](https://en.m.wikipedia.org/wiki/Thread_safety). So no, I cannot upvote this Answer. I did upvote the correct Answers [by Ole V.V.](https://stackoverflow.com/a/67215044/642706) and [by Arvind Kumar Avinash](https://stackoverflow.com/a/67213203/642706). – Basil Bourque Apr 23 '21 at 16:23
  • @Basil Bourque, am also taking back my upvote, since i have also mentioned about synchronization in simple date format. we can bring in other best practices in java to achieve other features we need accomplished from simple date format. so its a downvote from me as well for your answer –  Apr 26 '21 at 05:06