Format microseconds as hours:minutes:seconds, etc

28

2

The following is inspired by a question that came up on Stack Overflow today.

Given a number of microseconds, 0 <= n <= 86400000000 (e.g. 12345678900), output a formatted string hh:mm:ss:000:000, e.g. 03:25:45:678:900.

          0 -> '00:00:00:000:000'
12345678900 -> '03:25:45:678:900'
86400000000 -> '24:00:00:000:000'

I have a solution in Python in 209 bytes, but can it go lower?

Sam

Posted 2015-07-06T19:11:34.367

Reputation: 381

1I realise now that this isn't really a standard format for writing times, and hh:mm:ss.000000 would probably have been better (and easier). Still, can't go changing it now. – Sam – 2015-07-06T21:43:11.997

1Out of curiosity, what was the SO post? – Digital Trauma – 2015-07-06T23:25:52.937

@DigitalTrauma http://stackoverflow.com/questions/31251377 by a relatively new user. A correct answer had already been chosen, I was just playing around in IDLE and came up with a grotesque-looking dictionary comprehension that wasn't a particularly good answer to the question. Someone saw it and pointed out this site in a comment. I came here, wrote a question (slightly different to the SO post), and also wrote a much improved version of my answer (which I haven't posted, and which is now redundant to all the much more compact and imaginative answers below).

– Sam – 2015-07-07T07:19:19.980

Is there a limit on the number of hours in the input? – FUZxxl – 2015-07-07T10:19:51.020

Yes, arbitrarily I made it <= 86400000000 microsec, so <= 24 hours. – Sam – 2015-07-07T10:25:59.503

Sure would have saved me quite a few characters in my JavaScript answer if ISO format with the dot was allowed :/ Interesting challenge nonetheless :) – rink.attendant.6 – 2015-07-07T21:10:16.490

Welcome to PPCG! :) – undergroundmonorail – 2015-07-07T23:39:43.180

Answers

15

Python 2, 82 79 bytes

n=input()
o=""
for k in[1000]*2+[60]*3:o=":%0*d"%(k%7/2,n%k)+o;n/=k
print o[1:]

Builds the string, iterating through a series of divmods. The only fancy bit is the %7/2, which maps 1000 -> 3 and 60 -> 2.

Sp3000

Posted 2015-07-06T19:11:34.367

Reputation: 58 729

6

Pyth, 31 bytes

j\:_m>l`td+"00"%~/QddCM"ϨϨ<<<

Try it online: Demonstration

Explanation:

                                 implicit: Q = input number
                       "ϨϨ<<<   string "ϨϨ<<<" (5 chars but 7 bytes)
                     CM          convert each to number => [1000, 1000, 60, 60, 60]
    m                            map each number d to:
                 /Qd                divide Q by d
                ~                   and update Q with the new value
               %~ Q d               but use the old value to calculate Q mod d
          +"00"                     add the result to the string "00"
     >                              but only take the last 
      l`td                          len(str(d-1)) chars
   _                             revert order
j\:                              join the strings with ":"s

Jakube

Posted 2015-07-06T19:11:34.367

Reputation: 21 462

5

Bash + coreutils, 61

Shortest "mainstream" language so far...

a=%02d:
printf $a$a$a%03d:%03d `dc -e$1\ A00~rA00~r60~r60~rf`

Test output:

$ for t in 0 12345678900 86400000000; do ./usec.sh $t; echo; done
00:00:00:000:000
03:25:45:678:900
24:00:00:000:000
$ 

Digital Trauma

Posted 2015-07-06T19:11:34.367

Reputation: 64 644

4

CJam, 37 35 34 bytes

This is prettty long .. Golfing now..

ri[1e3_60__]{:ImdsIBb,0e[':@}%W%2>

UPDATE: 1 byte saved thanks to @Sp3000

Try it online here

Optimizer

Posted 2015-07-06T19:11:34.367

Reputation: 25 836

4

q (34)

I'm sure it can be shorter

":"sv 0 8 11__[;8]15$2_($)16h$1e3*

e.g.

q)f:":"sv 0 8 11__[;8]15$2_($)16h$1e3*
q)f 12345678900
"03:25:45:678:900"

skeevey

Posted 2015-07-06T19:11:34.367

Reputation: 4 139

4any online compilers ? in other words - How do I run it as a lazy person ? – Optimizer – 2015-07-06T21:32:17.603

32 bit version is available for free at http://www.kx.com

– skeevey – 2015-07-06T21:32:47.387

good spot. unfortunately the fix adds a few characters – skeevey – 2015-07-06T21:43:25.780

1you can cut more bytes here ":"sv 0 8 11__[;8]15$2_($)"n"$1e3* – WooiKent Lee – 2015-07-07T10:57:49.077

4

C, 97 bytes

q=1000,s=60;
#define f(n)printf("%02d:%02d:%02d:%03d:%03d",n/s/s/q/q,n/s/q/q%s,n/q/q%s,n/q%q,n%q)

Test Code:

int main(int intc, char **argv)
{
    long long n = atoll(argv[1]);
    f(n);
}

some user

Posted 2015-07-06T19:11:34.367

Reputation: 635

1Answers in C are supposed to be a complete, program; not a snippet. – NobodyNada - Reinstate Monica – 2015-07-07T01:58:40.713

It is not mentioned in the question. Is there some sort of global requirements? – some user – 2015-07-07T02:18:13.300

Loopholes that are forbidden by default – NobodyNada - Reinstate Monica – 2015-07-07T02:20:27.470

No. If you read the answer, it is just using C as an example. The rule would have applied to every language. Also, the answer is hotly disputed - see the highest rated comment. The bottom line is the Question needs to state it clearly if a full program is required. – some user – 2015-07-07T02:26:25.670

It has 41 upvotes and 9 downvotes, it's very much enforceable. That being said, you're defining a "function" which is an acceptable way to create an answer, so I would argue that this is fine. – undergroundmonorail – 2015-07-07T23:42:27.373

3Lots of answers on this site use functions instead of full programs - for example I don't think I have ever seen a Java answer that was a complete program... – Jerry Jeremiah – 2015-07-07T23:45:46.760

I tried this on ideone, it returns 03:00:25:000:045 for 12345678900, which is incorrect. – Kade – 2015-07-08T15:52:44.603

I blame ideone. My code works fine with gcc on Linux and Mac. On ideone, even printf("%d:%d", n/q%q, n%q); ended up with 678:0. (it should be 678:900) – some user – 2015-07-08T17:36:37.677

3

C#, 179 175 Bytes

When you have builtins at your disposal, why not use 'em?

static void Main(string[]a){var t=TimeSpan.FromTicks(long.Parse(Console.ReadLine())*10);Console.Write(t.ToString((t.Days<1?"hh":@"\2\4")+@"\:mm\:ss\:ffffff").Insert(12,":"));}

With better formatting:

static void Main(string[]a){
    var t = TimeSpan.FromTicks(long.Parse(Console.ReadLine())*10);
    Console.Write(t.ToString((t.Days<1?"hh":@"\2\4")+@"\:mm\:ss\:ffffff").Insert(12,":"));
    Console.Read();
}

Kade

Posted 2015-07-06T19:11:34.367

Reputation: 7 463

3

Julia, 110 96 95 bytes

t->(o="";for i=int([36e8,6e7,1e6,1e3,1]) x,t=t÷i,t%i;o*=lpad(x,i>1e3?2:3,0)*":"end;o[1:end-1])

This creates an unnamed function that accepts an integer as input and returns a string. To call it, give it a name, e.g. f=t->....

Ungolfed + explanation:

function f(t)
    # Initialize an output string
    o = ""

    # Loop over an array consisting of the number of microseconds in
    # an hour, minute, second, millisecond, and microsecond
    for i = int([36e8, 6e7, 1e6, 1e3, 1])

        # Get the quotient and remainder for microseconds into t,
        # setting t to be the remainder
        x, t = t ÷ i, t % i

        # Left-pad x with zeroes and append it to the output
        o *= lpad(x, i > 1e3 ? 2 : 3, 0) * ":"
    end

    # o has a trailing :, so return everything but the last character
    o[1:end-1]
end

Examples:

julia> f(12345678900)
"03:25:45:678:900"

julia> f(0)
"00:00:00:000:000"

julia> f(86400000000)
"24:00:00:000:000"

Alex A.

Posted 2015-07-06T19:11:34.367

Reputation: 23 761

Nice one. You get my vote because you inspired my Matlab answer :-) – Hoki – 2015-07-07T10:21:55.847

3

Excel, 65 63 characters

Assuming your microseconds is in A1:

=TEXT(A1/50/1200^3,"[HH]:mm:ss:")&RIGHT(TEXT(A1,"000\:000"),7)

Output:

        A              B
1            0  00:00:00:000:000
2  12345678900  03:25:46:678:900
3  86400000000  24:00:00:000:000

Hand-E-Food

Posted 2015-07-06T19:11:34.367

Reputation: 7 912

2

Perl, 141 78 bytes

printf"%02d"x3.%03d:%03d",$_/36e8,$_/6e7%60,$_/1e6%60,$_/1e3%1e3,$_‌​%1e3

77 bytes of code, +1 for the -n flag. Run with:

echo 12345678900 | perl -ne'printf"%02d"x3.%03d:%03d",$_/36e8,$_/6e7%60,$_/1e6%60,$_/1e3%1e3,$_‌​%1e3'

Thanks to Thomas Kwa and chilemagic for cutting my code size nearly in half.

ASCIIThenANSI

Posted 2015-07-06T19:11:34.367

Reputation: 1 935

I think 3600000000 can be 36e8. – lirtosiast – 2015-07-06T20:04:55.487

Instead of chomp($n=<STDIN>); you can run it as a one-liner with the -n flag (which counts as 1 character). You also don't need the int(..) around each $_. Applying Thomas's tip too we can get it down to echo 12345678900 | perl -ne'printf"%02d:%02d:%02d:%03d:%03d\n",$_/36e8,$_/6e7%60,$_/1e6%60,$_/1e3%1e3,$_%1e3' and there might even be a shorter way too! – hmatt1 – 2015-07-06T22:18:10.317

You don't need the \n in the output string either. You can also replace the string with "%02d:"x3 ."%03d:%03d" – hmatt1 – 2015-07-06T22:23:17.647

@chilemagic Does using "echo" count as an increase in bytes? – ASCIIThenANSI – 2015-07-07T17:22:40.290

@ASCIIThenANSI it doesn't because it isn't part of your program. The characters you would count are the ones between the single quotes, i.e. printf"%02d:%02d:%02d:%03d:%03d\n",$_/36e8,$_/6e7%60,$_/1e6%60,$_/1e3%1e3,$_‌​%1e3 and then you add an additional byte for the -n flag. If you used -nle for example, that would count as an additional 2 (for the n and the l). You get the - and the e (or E if you need to use say) for free. – hmatt1 – 2015-07-07T17:28:33.760

1

JavaScript (ES6), 128 118 116 111 bytes

There is probably some golfing potential in this.

f=t=>(t<864e8?new Date(t/1e3).toJSON().slice(11,-1):`24:00:00:000`).replace(`.`,`:`)+':'+('00'+t%1e3).slice(-3)

Demo

It is ES6 so Firefox only, for now anyways:

f=t=>(t<864e8?new Date(t/1e3).toJSON().slice(11,-1):`24:00:00:000`).replace(`.`,`:`)+':'+('00'+t%1e3).slice(-3)

// DEMO
document.body.innerHTML += '<br>' + f(0);
document.body.innerHTML += '<br>' + f(12345678020);
document.body.innerHTML += '<br>' + f(86400000000);

rink.attendant.6

Posted 2015-07-06T19:11:34.367

Reputation: 2 776

The first check is not needed, as the question is explicit: 0 <= n <= 86400000000 – edc65 – 2015-07-07T09:06:40.693

@edc65 Without the first check I can only get a range of 0 ≤ n < 86400000000, as 8.64e10 would roll over to the next day. – rink.attendant.6 – 2015-07-07T14:34:17.680

Oh right, I missed that. toJSON() instead of toISOString()? – edc65 – 2015-07-07T20:18:53.267

1

Matlab - 88 89 bytes

Gained one byte with a solution without using the built in function:

n=[36e8,6e7,1e6,1e3];f=@(t)sprintf('%02d:%02d:%02d:%03d:%03d',fix([t mod(t,n)]./[n 1]))

Create an inline function which takes a numeric input argument t and return a string.

it uses a vectorized combination of fix and mod to separate the time elements, then display.

it's a bit frustrating that the formatting of the output string takes so much, more than the calculations themselves ...

Test:

for t=[0 12345678900 86400000000]
    f(t)
end

ans =
00:00:00:000:000
ans =
03:25:45:678:900
ans =
24:00:00:000:000

89 bytes version:

f=@(t)sprintf('%s:%03d:%03d',datestr(fix(t/1e6)/86400,13),fix(mod(t,1e6)/1e3),mod(t,1e3))

It splits the number, uses a built-in function for the hh:mm:ss part, which cannot deal with microseconds so the string is completed with combination of fix and mod operations

Hoki

Posted 2015-07-06T19:11:34.367

Reputation: 271

1

C, 113 103 105 bytes

EDIT: shoved off some more bytes

FIX: removed long type, thanks to some user

Not the shortest C answer, but I had some fun with carriage returns so I felt like someone might like this.

i,k,p=16;
#define f(n)for(;i<5;p-=i++<2?4:3)k=i<2?1000:60,printf("%0*d%c\r",p,n%k,i?58:13),n/=k;puts("");

Call it like:

int main() {
    long long n = 12345678900;
    f(n);

    return 0;
}

Andrea Biondo

Posted 2015-07-06T19:11:34.367

Reputation: 1 452

Depends on platform, "long" could be just 32-bits. (see https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models). I avoided the problem by declaring "f" as macro instead of function.

– some user – 2015-07-07T20:07:50.027

I noticed that. I assumed GCC on x64, fixing it tomorrow. – Andrea Biondo – 2015-07-07T21:42:30.333

0

CoffeeScript, 127 bytes

Took the approach in ASCIIThenANSI's answer. It's too bad that the JavaScript Console API doesn't have format placeholders for padding numbers.

p=(a,b)->('00'+~~a).slice -b||-2
f=(t)->console.log '%s:%s:%s:%s:%s',p(t/36e8),p(t/6e7%60),p(t/1e6%60),p(t/1e3%1e3,3),p t%1e3,3

rink.attendant.6

Posted 2015-07-06T19:11:34.367

Reputation: 2 776

0

Powershell,153

$t=[timespan]::FromTicks(($a=$args[0]));"{0:D2}:{1:D2}:{2:D2}:{3:D3}:{4:000}"-f
[int]($t.TotalHours),$t.Minutes,$t.Seconds,$t.Milliseconds,(($a%1e4)/10)

Usage

powershell -nologo .\modprintsec.ps1 123456789000    
03:25:45:678:900   
powershell -nologo .\modprintsec.ps1 864000000000   
24:00:00:000:000   
powershell -nologo .\modprintsec.ps1 0   
00:00:00:000:000 

blabb

Posted 2015-07-06T19:11:34.367

Reputation: 219

0

F#, 111 92 102 bytes

First iteration: Base idea.

Second iteration: Smaller constants

Third iteration: Correct formatting for single digit portions.

Note this function must be given an int64 to work.

let s,t=60L,1000L
let f n=sprintf"%02d:%02d:%02d:%03d:%03d"(n/s/s/t/t)(n/s/t/t%s)(n/t/t%s)(n/t%t)(n%t)

Example outputs:

f 0L           -> "00:00:00:000:000"
f 12345678900L -> "03:25:45:678:900"
f 86400000000L -> "24:00:00:000:000"

Hand-E-Food

Posted 2015-07-06T19:11:34.367

Reputation: 7 912

0

PHP - 115 102 bytes

A solution in 155 bytes (wrapped here on 3 lines for readability):

$a=$argv[1];
$h=($a-($m=($a=($a-($s=($a=($a-($t=($a=($a-($u=$a%1000))/1000)%1000))/1000)%60))/60)%60))/60;
printf("%02d:%02d:%02d:%03d:%03d",$h,$m,$s,$t,$u);

The second line computes (from inside to outside) the exact values of the components starting with the microseconds.

The shorter version (115 bytes, wrapped on two lines for readability):

$u=$argv[1];$h=($m=($s=($t=$u/1000)/1000)/60)/60;
printf("%02d:%02d:%02d:%03d:%03d",$h,$m%60,$s%60,$t%1000,$u%1000);

It also uses embedded assignments to compute the convert the input number of microseconds in milliseconds, seconds, minutes and hours using floating point numbers. The modulus operator (%) and the decimal number format (%d) of printf() is then used to force them to integer numbers (the fractional part is ignored).

Another solution that uses the date functions (102 bytes)

$u=$argv[1];
echo gmdate("H:i:s",strtotime("@".substr($u,0,-6))),":",substr($u,-6,3),":",substr($u,-3);

The hours:minutes:seconds part is handled by the PHP date functions gmdate() and strtotime(), the milli- and micro-seconds are extracted as strings from the input value.

Usage:

$ php -r '$u=$argv[1];echo gmdate("H:i:s",strtotime("@".substr($u,0,-6))),":",substr($u,-6,3),":",substr($u,-3);' 7198898787; echo
01:59:58:898:787

axiac

Posted 2015-07-06T19:11:34.367

Reputation: 749

0

Java, 215 bytes

String f(long n){return p(n/3600000000l,2)+":"+p(n/60000000%60,2)+":"+p(n/1000000%60,2)+":"+p(n/1000%1000,3)+":"+p(n%1000,3);}String p(long n,int i){String s=String.valueOf(n);while(s.length()<i){s="0"+s;}return s;}

Method f does some calculations on n to work out the hours, minutes etc. and delegates to method p to format each value correctly.

Formatted:

String f(long n) {
    return p(n / 3600000000l, 2) + ":" + p(n / 60000000 % 60, 2) + ":" 
            + p(n / 1000000 % 60, 2) + ":" + p(n / 1000 % 1000, 3) + ":" + p(n % 1000, 3);
}

String p(long n, int i) {
    String s = String.valueOf(n);
    while (s.length() < i) {
        s = "0" + s;
    }
    return s;
}

Usage:

public void demo() {
    long n = 12345678900l;
    System.out.println(f(n));
}

RCB

Posted 2015-07-06T19:11:34.367

Reputation: 181

-1

Ruby - 82 Bytes

puts (t=Time.at(0,gets.to_i)).strftime("%2H:%2M:%2S:%3L:#{(t.usec%1000).to_s.rjust(3,?0)}")

Xenotoad

Posted 2015-07-06T19:11:34.367

Reputation: 151

2But I counted 91 bytes. It also only works in the UTC timezone. – jimmy23013 – 2015-07-07T20:57:47.850