It’s a time zone problem. Or more precisely, a problem of misusing SimpleDateFormat
for something that it wasn’t meant for. Here’s a way you can reproduce:
TimeZone.setDefault(TimeZone.getTimeZone("America/St_Johns"));
SimpleDateFormat timeFormatter = new SimpleDateFormat("mm:ss", Locale.getDefault());
System.out.println(timeFormatter.format(new Date(5*60*1000)));
Output from this snippet is:
35:00
Explanation:
new Date(5*60*1000)
produces a date-time of 5 minutes after the epoch, that is 00:05:00 UTC on January 1, 1970. At this time as at any other time, different zones of the world have different times. However, most time zones have an offset from UTC of a whole number of hours. So the time will be 5 minutes past the hour, and your formatter will print it as 05:00. This is why you didn’t notice the problem before. For example, in Berlin it will be 01:05:00, and in New York it will be 19:05:00 the evening before. However, there are also time zones that have offsets from UTC that are not a whole number of hours. For example Asia/Kolkata is at +05:30 and Asia/Kathmandu is at +05:45. In such a time zone, the time will not be 5 minutes past the hour, and you will get an unexpected result like the one you saw.
Suggested solutions include:
- Use
TimeUnit
for converting seconds into minutes and seconds and String.format
for formatting them into two digits each.
- If you want a nice solution and you’re OK with an external dependency on an old library in maintenance mode, look into the
PeriodFormatter
of Joda-Time.
Here’s an example of using TimeUnit
for calculating the parts to format as suggested in the first bullet:
long totalSeconds = TimeUnit.MINUTES.toSeconds(5); // 300
long minutes = TimeUnit.SECONDS.toMinutes(totalSeconds);
long secondsPart = totalSeconds - TimeUnit.MINUTES.toSeconds(minutes);
String formattedDuration = String.format("%02d:%02d", minutes, secondsPart);
System.out.println("Formatted duration: " + formattedDuration);
Output:
Formatted duration: 05:00
The ugly hack that I wouldn’t suggest would be to set the time zone of your formatter to UTC.
There’s a lot more inspiration in the question I already linked to in a comment. At time of writing it has 20 answers. I am repeating the link at the bottom.
And by the way, even for formatting and parsing dates and times, you may consider not using SimpleDateFormat
. It’s notoriously troublesome and long outmoded. Instead add ThreeTenABP to your Android project in order to use java.time
, the modern Java date and time API. It is so much nicer to work with.
Links