Given a number of seconds/milliseconds, what is the best method to gracefully/cleanly express this time interval in the user's language, using the Android values/strings.xml
API?
I am not asking for how to get the days/hours/minutes -- answers for that can be found in how to show milliseconds in days:hours:min:seconds and many other questions. For your information, my code for doing that:
int time1, time0; // given
int seconds, minutes, hours, days;
seconds = time1 - time0;
// TODO handle seconds <= 0
days = seconds / 86400;
hours = (seconds %= 86400) / 3600;
minutes = (seconds %= 3600) / 60;
seconds %= 60;
These are some methods I have brainstormed, but all have their disadvantages. What is the best method that doesn't have these problems?
printf
formatsstrings.xml
<string name="format_time" formatted="false">
%d day(s) %d hour(s) %d minute(s) %d second(s)
</string>
getString(R.string.format_time, days, hours, minutes, seconds);
As the (s)
s would have inspired you, we don't like to see 0 day(s) 0 hour(s) 0 minute(s) 1 second(s)
. Neither do we like 1 day(s) 0 hour(s) 0 minute(s) 0 second(s)
, but just 1 day
.
strings.xml
<string-array name="time_units">
<item>day(s)</item>
<item>hour(s)</item>
<item>minute(s)</item>
<item>second(s)</item>
</string-array>
<string name="time_value_unit_separator">" "</string>
<string name="time_inter_unit_separator">", "</string>
String[] units = getResources().getStringArray(R.array.time_units);
int[] values = {days, hours, minutes, seconds};
assert units.length == values.length;
StringBuilder builder = new StringBuilder();
final String valueUnitSeparator = getString(R.string.time_value_unit_separator);
final String unitSeparator = getString(R.string.time_inter_unit_separator);
for(int i = 0; i < units.length; i++){
if(values[i] > 0)
builder.append(values[i])
.append(valueUnitSeparator)
.append(units[i])
.append(unitSeparator);
}
return builder.substring(0, builder.length() - unitSeparator.length());
seconds 5
rather than 5 seconds
?30 seconds, 2 minutes
rather than 2 minutes 30 seconds
?Regarding your first part with concatenation, there's no clean way to do it using the Android framework. The "official" reason would be it's slower to concat than it is to use formatting, but you're talking about milliseconds here. Worst case here, you're only going to update the text every one second so it's not a pain and nobody would notice.
There's a thing called Plurals which you can use to get different strings (i.e. "Hour" for 1 hour and "Hours" for >1 hour). So you could get a utility method like so and just use that:
public static String getHourString(Context ctx, int hours) {
if (hours == 0) {
return "";
} else {
return ctx.getResources().getQuantityString(R.plurals.hoursString, hours, hours);
}
}
public static String getMinutesString(Context ctx, int mins) {
if (mins == 0) {
return "";
} else {
return ctx.getResources().getQuantityString(R.plurals.minutesString, mins, mins);
}
}
public static String getSecondsString(Context ctx, int secs) {
if (secs == 0) {
return "";
} else {
return ctx.getResources().getQuantityString(R.plurals.secondsString, secs, secs);
}
}
For time formatting, there is the Java time formatting and Joda-Time has some help with date locale as well.
Though that is for time and date formats. Your method (e.g. 1 minute, 1 second) isn't a standard as far as I know. For your method, you'll have to use Locale Directories and create a string for each language that you want to support. Although, since you have to manually concat the strings, this probably won't help you much.