java.time.Duration through desugaring and String.format()
Use java.time, the modern Java date and time API, for your time work.
I haven’t got an Android development environment, but I expect the following to work with desugaring (see the link below). It works with desktop Java version 9 and later.
int leftTimeInMillis = 12_728_918;
Duration timeLeft = Duration.ofMillis(leftTimeInMillis);
String formattedTimeLeft = String.format("%02d:%02d:%02d",
timeLeft.toHours(), timeLeft.toMinutesPart(), timeLeft.toSecondsPart());
System.out.println(formattedTimeLeft);
Output is the required:
03:32:08
If for some reason instead of desugaring your are using ThreeTenABP, I believe that the toMinutesPart
and toSecondsPart
methods are not included. Then the conversion takes a little bit more:
Duration timeLeft = Duration.ofMillis(leftTimeInMillis);
long hours = timeLeft.toHours();
timeLeft = timeLeft.minusHours(hours);
long minutes = timeLeft.toMinutes();
timeLeft = timeLeft.minusMinutes(minutes);
long seconds = timeLeft.getSeconds();
String formattedTimeLeft = String.format("%02d:%02d:%02d",
hours, minutes, seconds);
Output is the same as before.
Alternative: Time4A
If you’re happy with an extensive external library for date and time, an option is Time4A, the Android version of Time4J. It offers a solution that is a bit more elegant and more in line with what you tried yourself. I prefer to declare a static formatter:
private static final Duration.Formatter<ClockUnit> M_TIME_FORMAT
= Duration.formatter(ClockUnit.class, "hh:mm:ss");
Now formatting goes like:
int leftTimeInMillis = 12_728_918;
Duration<ClockUnit> timeLeft = Duration.of(leftTimeInMillis, ClockUnit.MILLIS)
.with(Duration.STD_CLOCK_PERIOD);
String formattedTimeLeft = M_TIME_FORMAT.format(timeLeft);
System.out.println(formattedTimeLeft);
03:32:08
Again I have developed my code on desktop Java using Time4J.
What went wrong in your code?
What happened in your code? Where did those 2 hours come from? SimpleDateFormat
was designed in the 1990’s and was always for formatting and parsing a point in time, never an amount of time. So it takes your number, 12 728 918, to mean a point in time this many milliseconds after the Java epoch of Jan 1 1970 at start of day in UTC. In other words you are trying to format an instant of 1970-01-01T03:32:08.918Z. Since the time zone setting of your device (a guess would be Europe/Athens) was 2 hours ahead of UTC in the winter of 1970, the date and time used for formatting is 1970-01-01T05:32:08.918+02:00[Europe/Athens]. Which is why you got 05:32:08
.
Assuming that you did not have a time in New Year’s night in 1970 in mind, what you are doing is wrong, and even if you could make it work, it will confuse everyone reading your code. Also if one day the anount of milliseconds exceeds 24 hours, the whole days will not be printed, probably causing great confusion. Don’t use SimpleDateFormat
for this purpose. And consider never using SimpleDateFormat
at all since that class is notoriously troublesome and long outdated.
Question: Doesn’t java.time require Android API level 26?
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
- In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
- In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
- On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from
org.threeten.bp
with subpackages.
Links