Int->String formatting method

D

Deniz Dogan

Hello again! Yes, I have yet another problem for all of you great
programmers in here.

This should actually be a pretty easy task to complete, but somehow the
blood in my veins doesn't seem to flow the right way just now. Here's
the problem:
I have an amount of milliseconds, in the range [0,Integer.MAX_VALUE] and
I want to format it to a String of the format "HH:nn:ss,mmm" where HH
ranges between 00-99, nn between 00-59, ss between 00-59 and mmm between
000-999 (all of the ranges inclusive).
The only thing I can come up with now as a solution is a bunch of
if-then-else statements, but really now, we shouldn't have to go and do
that, do we?

I love stating problems. Looking forward to your help.

/Deniz Dogan
 
D

Deniz Dogan

Deniz said:
Hello again! Yes, I have yet another problem for all of you great
programmers in here.

This should actually be a pretty easy task to complete, but somehow the
blood in my veins doesn't seem to flow the right way just now. Here's
the problem:
I have an amount of milliseconds, in the range [0,Integer.MAX_VALUE] and
I want to format it to a String of the format "HH:nn:ss,mmm" where HH
ranges between 00-99, nn between 00-59, ss between 00-59 and mmm between
000-999 (all of the ranges inclusive).
The only thing I can come up with now as a solution is a bunch of
if-then-else statements, but really now, we shouldn't have to go and do
that, do we?

I love stating problems. Looking forward to your help.

/Deniz Dogan

Disregard my post, a friend of mine solved it on four rows of code and
O(1) fashion.
 
O

Oliver Wong

Deniz Dogan said:
Deniz said:
Hello again! Yes, I have yet another problem for all of you great
programmers in here.

This should actually be a pretty easy task to complete, but somehow the
blood in my veins doesn't seem to flow the right way just now. Here's the
problem:
I have an amount of milliseconds, in the range [0,Integer.MAX_VALUE] and
I want to format it to a String of the format "HH:nn:ss,mmm" where HH
ranges between 00-99, nn between 00-59, ss between 00-59 and mmm between
000-999 (all of the ranges inclusive).
The only thing I can come up with now as a solution is a bunch of
if-then-else statements, but really now, we shouldn't have to go and do
that, do we?

I love stating problems. Looking forward to your help.

/Deniz Dogan

Disregard my post, a friend of mine solved it on four rows of code and
O(1) fashion.

You should have post the solution, in case someone in the future
stumbles upon this post via google and has a similar problem and is looking
for the solution.

here's my guess at the solution:

public static String toTimeString(long milliseconds) {
final long MS_PER_SEC = 1000;
final long MS_PER_MIN = MS_PER_SEC * 60;
final long MS_PER_HOUR = MS_PER_MIN * 60;
final long hours = milliseconds / MS_PER_HOUR;
milliseconds %= MS_PER_HOUR;
final long minutes = milliseconds / MS_PER_MIN;
milliseconds %= MS_PER_MIN;
final long seconds = milliseconds / MS_PER_SEC;
milliseconds %= MS_PER_SEC;
StringBuffer sb = new StringBuffer();
sb.append(hours);
sb.append(":");
sb.append(minutes);
sb.append(":");
sb.append(seconds);
sb.append(",");
sb.append(milliseconds);
return sb.toString();
}

- Oliver
 
D

Deniz Dogan

Oliver said:
Deniz Dogan said:
Deniz said:
Hello again! Yes, I have yet another problem for all of you great
programmers in here.

This should actually be a pretty easy task to complete, but somehow
the blood in my veins doesn't seem to flow the right way just now.
Here's the problem:
I have an amount of milliseconds, in the range [0,Integer.MAX_VALUE]
and I want to format it to a String of the format "HH:nn:ss,mmm"
where HH ranges between 00-99, nn between 00-59, ss between 00-59 and
mmm between 000-999 (all of the ranges inclusive).
The only thing I can come up with now as a solution is a bunch of
if-then-else statements, but really now, we shouldn't have to go and
do that, do we?

I love stating problems. Looking forward to your help.

/Deniz Dogan

Disregard my post, a friend of mine solved it on four rows of code and
O(1) fashion.

You should have post the solution, in case someone in the future
stumbles upon this post via google and has a similar problem and is
looking for the solution.

here's my guess at the solution:

public static String toTimeString(long milliseconds) {
final long MS_PER_SEC = 1000;
final long MS_PER_MIN = MS_PER_SEC * 60;
final long MS_PER_HOUR = MS_PER_MIN * 60;
final long hours = milliseconds / MS_PER_HOUR;
milliseconds %= MS_PER_HOUR;
final long minutes = milliseconds / MS_PER_MIN;
milliseconds %= MS_PER_MIN;
final long seconds = milliseconds / MS_PER_SEC;
milliseconds %= MS_PER_SEC;
StringBuffer sb = new StringBuffer();
sb.append(hours);
sb.append(":");
sb.append(minutes);
sb.append(":");
sb.append(seconds);
sb.append(",");
sb.append(milliseconds);
return sb.toString();
}

- Oliver

And here's my friend's solution:

public static String formatMillis(int millis) {
int ihh = millis/3600000; //amount of hours
int inn = (millis - ihh*3600000) / 60000; //amount of minutes
int iss = (millis - (ihh*3600000) - (inn * 60000)) / 1000; //amount
of seconds
int immm = (millis - (ihh*3600000) - (inn * 60000)) - iss*1000;
//amount of milliseconds
//String representations of the integers:
String mmm = "" + immm, ss = "" + iss, nn = "" + inn, hh = "" + ihh;
//Making sure the lengths of the Strings are correct:
if (mmm.length() == 1) mmm = "00" + mmm;
else if (mmm.length() == 2) mmm = "0" + mmm;
if (ss.length() == 1) ss = "0" + ss;
if (nn.length() == 1) nn = "0" + nn;
if (hh.length() == 1) hh = "0" + hh;
return hh + ":" + nn + ":" + ss + "," + mmm;
}

I have a question for you Oliver (or anyone else who'd want to answer
this question), is your solution faster than mine? I considered using
the modulo operator, but I wasn't sure how the JVM would implement it. I
figured it would just do a lot of division operations until it couldn't
divide it any more, but perhaps it implements it in a different manner?

- Deniz Dogan
 
T

Thomas Weidenfeller

Deniz said:
I have a question for you Oliver (or anyone else who'd want to answer
this question), is your solution faster than mine?

It does not matter. Unless you have evidence that an implementation
really affects an application's performance in an unacceptable way there
are more important criteria to judge an algorithm's implementation. E.g.
maintainability, or robustness regarding change.
I considered using
the modulo operator, but I wasn't sure how the JVM would implement it. I
figured it would just do a lot of division operations until it couldn't
divide it any more, but perhaps it implements it in a different manner?

That would be an extremely brain-dead thing to do. Sun programmers do a
lot of strange and stupid things in the JDK, but I can't imagine they
would do such a brain-dead modulo operator in the VM. They probably use
the C modulo operator which is probably translated into a modulo
assembler instruction - if the particular CPU provides such an
instruction. Or it is translated into a call into some assembler library
- if an old CPU doesn't provide such an assembler instruction or one
that doesn't fit the JLS modulo definition.

Simplified and broad speaking, the reminder is a by-product of binary
integer division algorithms, and as such usually does take the same or
similar time as a single integer division, whether done in hardware
(CPU' ALU) or software. Don't they teach binary arithmetic in school
any more?

But again, it doesn't matter. As long as you have no evidence that a
particular operation affects your application in an unacceptable way,
you are wasting your time trying to "optimize" such things.

/Thomas
 
W

Wibble

Thomas said:
It does not matter. Unless you have evidence that an implementation
really affects an application's performance in an unacceptable way there
are more important criteria to judge an algorithm's implementation. E.g.
maintainability, or robustness regarding change.


That would be an extremely brain-dead thing to do. Sun programmers do a
lot of strange and stupid things in the JDK, but I can't imagine they
would do such a brain-dead modulo operator in the VM. They probably use
the C modulo operator which is probably translated into a modulo
assembler instruction - if the particular CPU provides such an
instruction. Or it is translated into a call into some assembler library
- if an old CPU doesn't provide such an assembler instruction or one
that doesn't fit the JLS modulo definition.

Simplified and broad speaking, the reminder is a by-product of binary
integer division algorithms, and as such usually does take the same or
similar time as a single integer division, whether done in hardware
(CPU' ALU) or software. Don't they teach binary arithmetic in school
any more?

But again, it doesn't matter. As long as you have no evidence that a
particular operation affects your application in an unacceptable way,
you are wasting your time trying to "optimize" such things.

/Thomas
That said, Oliver's use of StringBuffer instead of + will
make his code much faster.
 
D

Deniz Dogan

Wibble said:
Thomas Weidenfeller wrote: [snip]
That said, Oliver's use of StringBuffer instead of + will
make his code much faster.

I trust you on that one, but I feel obliged to ask why?

- Deniz Dogan
 
O

Oliver Wong

Deniz Dogan said:
Wibble said:
Thomas Weidenfeller wrote: [snip]
That said, Oliver's use of StringBuffer instead of + will
make his code much faster.

I trust you on that one, but I feel obliged to ask why?

First of all, my code is incorrect, because I forgot to check if I need
to prefix '0' before certain of the numbers. For example, I might generate
"1:1:1,1" instead of "01:01:01,0001".

The exact reason that StringBuffer is faster is that String is difficult
to explain. With a lot of hand waving, the overall reason is String is
immutable, but StringBuilder is not, so String has to do a lot of
contortions to progressively build up the output String, whereas
StringBuilder can perform the String construction in the "obvious" way.

- Oliver
 
O

Oliver Wong

Thomas Weidenfeller said:
That would be an extremely brain-dead thing to do. Sun programmers do a
lot of strange and stupid things in the JDK, but I can't imagine they
would do such a brain-dead modulo operator in the VM. They probably use
the C modulo operator which is probably translated into a modulo assembler
instruction - if the particular CPU provides such an instruction. Or it is
translated into a call into some assembler library - if an old CPU doesn't
provide such an assembler instruction or one that doesn't fit the JLS
modulo definition.

I think that modern x86 Intel and AMD chips have a built in modulo
operator. For CPUs which don't have modulo, you could implement it like
this:

C = A % B

temp = A / B
temp = B * A
C = A - temp

So worst case, an integer modulo would take up 3 "normal" integer
operations worth of time. The usage of "temp" implies an extra register, but
"temp" and "C" could use the same register.

- Oliver
 
D

Deniz Dogan

Oliver said:
Deniz Dogan said:
Wibble said:
Thomas Weidenfeller wrote: [snip]
That said, Oliver's use of StringBuffer instead of + will
make his code much faster.

I trust you on that one, but I feel obliged to ask why?

First of all, my code is incorrect, because I forgot to check if I
need to prefix '0' before certain of the numbers. For example, I might
generate "1:1:1,1" instead of "01:01:01,0001".

Yes, that's exactly why I didn't quite see how your code was faster.
(And also, the milliseconds should be 001, not 0001 ;-))
The exact reason that StringBuffer is faster is that String is
difficult to explain. With a lot of hand waving, the overall reason is
String is immutable, but StringBuilder is not, so String has to do a lot
of contortions to progressively build up the output String, whereas
StringBuilder can perform the String construction in the "obvious" way.

I think I got it, thanks a lot for your help!
 
G

Guest

Thomas said:
It does not matter. Unless you have evidence that an implementation
really affects an application's performance in an unacceptable way there
are more important criteria to judge an algorithm's implementation. E.g.
maintainability, or robustness regarding change.

Yep.

I would consider the following good enough even though
it is 3 times slower than the proposed code:

private final static DateFormat df = new
SimpleDateFormat("HH:mm:ss,SSS");
public static String formatMillis3(int millis) {
return df.format(new Date(millis -
TimeZone.getDefault().getOffset(millis)));
}

Arne
 
G

Guest

Wibble said:
That said, Oliver's use of StringBuffer instead of + will
make his code much faster.

No it does not.

When I test the String code and the StringBuffer code
(fixed to properly add leading zeroes), then the String
code as actually fastest.

That may vary based on platform, Java version etc..

But it is not much faster.

There are simply too few appends on too short
strings to really bring up the StringBuffer advantage.

Arne
 
D

Deniz Dogan

Arne said:
Yep.

I would consider the following good enough even though
it is 3 times slower than the proposed code:

private final static DateFormat df = new
SimpleDateFormat("HH:mm:ss,SSS");
public static String formatMillis3(int millis) {
return df.format(new Date(millis -
TimeZone.getDefault().getOffset(millis)));
}

Arne

This code was actually what I was looking for in the first place! I
love pretty Java, no matter how slow it is.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top