Reputation: 808
I want to convert my timestamp into XXhours:YYminutes string. My approach sometimes works correctly unless it’s obtaining greater values. For example, the
193500000 -> 05hours:45minutes (Wrong, correct is 53hours:45minutes)
60300000 -> 16hours:45minutes (correct)
63900000 -> 17hours:45minutes (correct)
108000000-> 06hours:00minutes (Wrong, correct is 30hours:00minutes)
117000000 -> 08hours:30minutes (Wrong, correct is 32hours:30minutes)
SimpleDateFormat dateFormat = new SimpleDateFormat("HH'hours' mm'minutes'");
dateFormat.setTimeZone( TimeZone.getTimeZone( "GMT"));
String string = dateFormat.format(totalTime);
Upvotes: 2
Views: 1975
Reputation: 79015
SimpleDateFormat
is the wrong class for this requirementYour requirement is to calculate the duration instead of a date-time. SimpleDateFormat
or java.time.format.DateTimeFormatter
(part of the modern date-time API) should be used to represent a date/time/date-time i.e. something which represents a point in time instead of a period/duration of time. A thumb rule to remember this is:
SimpleDateFormat
or java.time.format.DateTimeFormatter
for something which you refer with since
in English grammar Tense.for
in English grammar Tense.Check The Difference between Since and For – English grammar
In order to get the duration from milliseconds, you can use java.time.Duration
which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenience methods were introduced.
Demo:
import java.time.Duration;
public class Main {
public static void main(String[] args) {
Duration duration = Duration.ofMillis(193500000);
// Default format
System.out.println(duration);
// Custom format
// ####################################Java-8####################################
String formattedElapsedTime = String.format("%02d hours %02d minutes", duration.toHours(),
duration.toMinutes() % 60);
System.out.println(formattedElapsedTime);
// ##############################################################################
// ####################################Java-9####################################
formattedElapsedTime = String.format("%02d hours %02d minutes", duration.toHours(), duration.toMinutesPart());
System.out.println(formattedElapsedTime);
// ##############################################################################
}
}
Output:
PT53H45M
53 hours 45 minutes
53 hours 45 minutes
Learn about the modern date-time API from Trail: Date Time.
Upvotes: 1
Reputation: 86223
The answer by talex is correct that you should use a Duration
for this. In Java 9 formatting the Duration
has become a bit easier and more straightforward to write and read:
public static String formatDuration(long totalTimeMillis) {
Duration totalDuration = Duration.ofMillis(totalTimeMillis);
return String.format(Locale.ENGLISH,
"%02d hours %02d minutes",
totalDuration.toHours(),
totalDuration.toMinutesPart());
}
We no longer need the modulo operation (or similar) for finding the minutes. To demonstrate I called the above method using your time values from the question:
System.out.println(formatDuration(60300000));
System.out.println(formatDuration(63900000));
System.out.println(formatDuration(108000000));
System.out.println(formatDuration(117000000));
System.out.println(formatDuration(193500000));
It prints the results you asked for:
16 hours 45 minutes
17 hours 45 minutes
30 hours 00 minutes
32 hours 30 minutes
53 hours 45 minutes
I have put in a space between the number and the unit, I find it more readable that way, you can just remove it if you don’t want it.
The %02d
specifier in the format string makes sure you get two digits with a leading zero as necessary as in the question: formatDuration(14700000)
, for example yields 04 hours 05 minutes
.
SimpleDateFormat
was meant for formatting a date and/or a time of day, not a duration or elapsed time. I say “was” because that class is now long outdated, and since it was also notoriously troublesome I recommend you never use it again. For formatting a date or hour of day use a DateTimeFormatter
from java.time
.
Upvotes: 2
Reputation: 20455
Unfortunately it is impossible with SimpleDateFormat
.
"HH" means hour in day. If you date is more than 24 hour it will result modulo 24.
I suggest you to write custom code with new time API.
Here is example:
Duration duration = Duration.ofMillis(193500000);
long minutes = duration.toMinutes() % 60;
long hours = duration.toHours();
System.out.println("" + hours + "hours:"+minutes+"minutes");
Upvotes: 2
Reputation: 4303
Carefully read this again: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
The HH is hours in a day, never more than 24 :-)
What you want is probably something like this:
int msecPerHour = 3600*1000;
int hours = totalTime/msecPerHour;
int msecPerMinute = 60*1000;
int minutes = totalTime/msecPerMinute - hours*60;
String str = "" + hours + " hours " + minutes + " minutes";
Upvotes: 2
Reputation: 1993
It looks like you are trying to convert durations, not date-times. SimpleDateFormat
is for formatting date-times into different formats for different Locales.
You might be looking for something like this for converting between durations:
String.format("%d hours, %d minutes",
TimeUnit.MILLISECONDS.toHours(millis),
TimeUnit.MILLISECONDS.toMinutes(millis) -
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis))
);
Upvotes: 0
Reputation: 10151
193500000 -> 05hours:45minutes (Wrong, correct is 53hours:45minutes)
That's because 53 hours = 2 days and 5 hours
60300000 -> 16hours:45minutes (correct)
63900000 -> 17hours:45minutes (correct)
108000000-> 06hours:00minutes (Wrong, correct is 30hours:00minutes)
That's because 30 hours = 1 day and 6 hours
117000000 -> 08hours:30minutes (Wrong, correct is 32hours:30minutes)
That's because 32 hours = 1 day and 8 hours
If you only want to calculate the number of hours from ms:
193500000/(1000*60*60) = number of hours
(193500000/(1000*60))%60 = number of remaining minutes
Upvotes: 1