# ASCII clock with dot & comma time markers

### Introduction

Imagine that line of chars is in fact two rows. Upper row - dots - represents hours (24 hour system), while lower - commas - represents minutes. One character can represent hour, minute or both - whenever it's possible.

At first probably you'd have to convert minutes since midnight to hours and minutes.

The result is the string showing current time in "dot format". The dot count (apostrophe counts here as a dot and will be called so!) is the hour count since midnight and comma count is minutes count. I'll show a few examples to make it clear.

• (Remark) hh:mm - result
• (Only hours) 05:00 - '''''
• (Only minutes) 00:08 - ,,,,,,,,
• (hours < minutes) 03:07 - ;;;,,,,
• (hours > minutes) 08:02 - ;;''''''
• (hours = minutes) 07:07 - ;;;;;;;
• (the start of the day) 00:00 -   (empty result)

Notice that "both" character can be used max 23 times - for 23:xx, where xx is 23 or more.

### Symbols

If character have to (see rule 5.) be escaped in your language, you could changed it to one of alternatives. If said alternatives aren't enough, you may use other symbols - but keep it reasonable. I just don't want escaping to be a barrier.

• ; (semicolon) - marker for both hours and minutes (alt: :)
• ' (apostrophe) - marker for hours (alt: '°)
• , (comma) - marker for minutes (alt: .)

1. The code with the least amount of bytes wins!
2. You have to use both symbol whenever it's possible. For 02:04 the result can't be '',,,,, nor ;',,,. It have to be ;;,,
3. Input - can be script/app parameter, user input (like readline) or variable inside code
3.1. If the variable inside code is used, then its lenght have to be the longest possible. It's 1439 (23:59), so it would look like t=1439
4. The common part which is symbolized by "both" character (12 in 12:05, 3 in 03:10) must be placed on the beginning of the string
5. Symbols can be replaced to alternatives only if they would have to be escaped in your code.
6. Input is given in minutes after 00:00. You can assume that this is a non-negative integer.

### Test cases

Input: 300
Output: '''''

Input: 8
Output: ,,,,,,,,

Input: 187
Output: ;;;,,,,

Input: 482
Output: ;;''''''

Input: 427
Output: ;;;;;;;

Input: 0
Output:  (empty)

• No problem! It is a very good first post and a nice challenge :) Dec 23, 2015 at 2:45
• this looks so good with just semicolons and commas, but apostrophes muck it all up :( Dec 23, 2015 at 2:55
• Actually 1439 is 23:59 and not 1339. (23 x 60 + 59). Dec 23, 2015 at 9:04
• Thank all of you for good words! :) @Sparr, yeah, that's the bad point :( Have you idea how it could be replaced? insertusernamehere, of course that's right! Fixed :) Dec 23, 2015 at 18:33
• 3.1 is kind of weird... What does it mean? Does the variable have to be called qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq?
– user46167
Dec 23, 2015 at 21:45

# Pyth, 19 bytes

:.iF*V.DQ60J"',"J\;


Test suite

:.iF*V.DQ60J"',"J\;
.DQ60            Divmod the input by 60, giving [hours, minutes].
J"',"       Set J equal to the string "',".
*V                 Perform vectorized multiplication, giving H "'" and M ','.
.iF                   Interleave the two lists into a single string.
:               J\;    Perform a substitution, replacing J with ';'.


## CJam, 2220 19 bytes

Takes input from STDIN:

ri60md]',.*:.{;K+}


Test it here.

### Explanation

ri     e# Read input and convert to integer.
60md   e# Divmod 60, pushes hours H and minutes M on the stack.
]      e# Wrap in an array.
',    e# Push the string representation of the comma character which is "',".
.*     e# Repeat apostrophe H times and comma M times.
:.{    e# Apply this block between every pair of characters. This will only applied to
e# first N characters where N = min(hours,minutes). The others will remain
e# untouched. So we want the block to turn that pair into a semicolon...
K+   e#   Add 20 to the apostrophe to turn it into a semicolon.
}


It was really lucky how well things worked together here, in particular the assignment of hours to ' and minutes to , such that the order of hours and minutes on the stack matched up with the string representation of the character.

This is the only 3-byte block I've found so far. There were tons of 4-character solutions though:

{;;';}
{';\?}
{^'0+}
{^'F-}
{-'@+}
{-'6-}
...


# GNU Sed, 37

Score includes +1 for -E option to sed.

I wasn't particularly impressed with the golfiness of my bash answer, so I thought I'd try with sed for the fun.

Input is in unary, as per this meta-answer.

y/1/,/          # Convert unary 1's to commas (minutes)
s/,{60}/'/g     # divmod by 60.  "'" are hours
:               # unnamed label
s/(.*)',/;\1/   # replace an apostrophe and comma with a semicolon
t               # jump back to unnamed label until no more replacements


Try it online

• unnamed label?? Dec 23, 2015 at 7:32
• @mikeserv, see Digital Trauma's related tip in Tips for golfing in sed. Dec 23, 2015 at 12:26
• @manatwork - i think it must be a GNU bug. Dec 23, 2015 at 18:12
• @mikeserv - but using bugs is OK as well, right? I'm not asking to mock you, I just don't know :) Dec 23, 2015 at 18:40
• @Krzysiu - ok? hmm. on this site i think it would be a mark of excellence. otherwise, almost definitely no. when programmers stray from API and use implementation details programs become version/implementation dependent - which is a bad thing. Dec 23, 2015 at 18:59

## Python 2, 56 bytes

def g(t):d=t%60-t/60;print(t/60*";")[:t%60]+","*d+"'"*-d


A function that prints (one char shorter than t=input();).

The method is similar to Loovjo's. The number of , is the different between minutes and hours, with an implicit minimim of 0. For ', it's the negation. For ;, computes the min implicitly by taking as many ; as hours, then truncating to the number of minutes.

It saves chars to save d, but not the number of hours and minutes here. The analogue with lambda was two chars longer (58), so the variable assignments are worth it.

lambda t:(t%60*";")[:t/60]+","*(t%60-t/60)+"'"*(t/60-t%60)


Processing the input directly didn't save chars either (58):

h,m=divmod(input(),60);d=m-h;print(";"*m)[:h]+","*d+"'"*-d


Another strategy with slicing, much longer (64):

def g(t):m=t%60;h=t/60;return(";"*m)[:h]+(","*m)[h:]+("'"*h)[m:]


# Retina, 24

Trivial port of my sed answer.

Input is in unary, as per this meta-answer.

1
,
,{60}
'
+(.*)',
;$1  Try it online. # Pure Bash (no external utilities), 103 p()(printf -vt %$2s;printf "${t// /$1}")
p \; $[h=$1/60,m=$1%60,m>h?c=m-h,h:m] p ,$c
p \' $[m<h?h-m:0]  Thanks to @F.Hauri for saving 2 bytes. • Nice! But you could save 2 chars by swapping $1 and $2 in p() and write p ,$c at line 3. Dec 23, 2015 at 21:03
• Yes, but as it's used only in a printf "%s", having c empty will work fine (while not reused) Dec 24, 2015 at 7:35
• @F.Hauri Now I get it - thanks! Dec 24, 2015 at 22:43

# C, 119 bytes

#define p(a,b) while(a--)putchar(b);
main(h,m,n){scanf("%d",&m);h=m/60;m%=60;n=h<m?h:m;h-=n;m-=n;p(n,59)p(h,39)p(m,44)}


Detailed

// macro: print b, a times
#define p(a,b) while(a--)putchar(b)

int main(void)
{
int h,m,n;

h=m/60;m%=60;    // get hours:minutes
n=h<m?h:m;       // get common count
h-=n;m-=n;       // get remaining hours:minutes

p(n,59);        // print common
p(h,39);        // print remaining hours
p(m,44);        // print remaining minutes

return 0;
}

• Using putchar & integer literals as characters saves one byte, pulling the semicolons inside the macro saves two more :) Dec 23, 2015 at 22:35
• @Quentin note taken, saved 5 bytes Dec 24, 2015 at 7:09
• You can lose the space before your while in your #define macro. -1 byte Mar 2, 2017 at 8:41
• You can also save some more bytes by just making p(a,b) a function instead of a macro. (And sprinkling a few more semi-colons to your main function) Mar 2, 2017 at 8:48

g(h,m)=id=<<zipWith replicate[min h m,h-m,m-h]";',"
g.(divMod60)


Usage example:

(g.(divMod60)) 482


The clever bit here is that replicate will return the empty string if the length given is negative or zero so I can apply it to both differences and only the positive one will show up. The first part is easy, since the number of semicolons is just the minimum of the two. Then zipWith applies the function to the corresponding items.

EDIT: Realized I was using the wrong char for minutes

EDIT 2: Saved 2 bytes thanks to @Laikoni

• You can save two bytes by replacing concat$ with id=<<. Mar 2, 2017 at 8:38 # JavaScript (ES6) 69 m=>";".repeat((h=m/60|0)>(m%=60)?m:h)+",'"[h>m|0].repeat(h>m?h-m:m-h)  # Powershell, 99 85 bytes param($n)";"*(($m=$n%60),($h=$n/60))[($b=$m-gt$h)]+"'"*(($h-$m)*!$b)+","*(($m-$h)*$b) Using Loovjo's method, this is my powershell implementation. ungolfed param($n)
# set the number of minutes and hours, and a boolean which one is bigger
# and also output the correct number of ;s
";"*(($m=$n%60),($h=$n/60))[($b=$m-gt$h)]+ # add the difference between h and m as 's but only if h > m "'"*(($h-$m)*!$b)+
# add the difference between m and h as ,s but only if m > h
","*(($m-$h)*$b)  Saved 14 bytes thanks to AdmBorkBork • You can save by using a pseudo-ternary for the first one, moving the $m and $h declarations into it, and then using Boolean multiplication. Like so -- param($n)';'*(($m=$n%60),($h=$n/60))[($b=$m-gt$h)]+'°'*(($h-$m)*!$b)+','*(($m-$h)*$b) Mar 2, 2017 at 14:01 # Python 3, 98 bytes d=int(input());m=d%60;h=int((d-m)/60) if m>=h:print(";"*h+","*(m-h)) else:print(";"*(m)+"'"*(h-m))  Probably not the best answer, but it was a lot of fun! # Python 2, 61 bytes t=input();m,h=t%60,t/60 print";"*min(h,m)+","*(m-h)+"'"*(h-m)  Explaination: t=input(); # Read input m, t%60, # Do a divmod, h = div, m = mod h= t/60 print";"*min(h,m)+ # Print the minimum of the h and m, but in ";"s ","*(m-h)+ # Print (m-h) ","s (if m-h is negative, print nothing) "'"*(h-m) # Print (h-m) "'"s (if h-m is negative, print nothing)  # PHP, 81 bytes I went for the variable input as it is shorter than reading from STDIN or taking command line arguments. for($_=1439;$i<max($h=0|$_/60,$m=$_%60);++$i)echo$i<$h?$i<min($h,$m)?';':"'":",";  • I thought that I know PHP rather well, but I see | for the first time. I think I'll use it to exercise a bit - I'll analyze it :) Dec 23, 2015 at 18:38 • Fails for 240. Try $i>=min($h,$m)?$h<$m?",":"'":";" (+1 byte). Or use for($_=1439;$i<max($h=0|$_/60,$m=$_%60);)echo"',;"[$i++<min($h,$m)?2:$h<$m]; (76 bytes). Btw: single quote renders -r impossible; so you should use backtick for hours if in a string or ° standalone (needs no quotes -> -1 byte). Mar 1, 2017 at 16:10 # JavaScript (ES6), 77 71 bytes x=>';'[r='repeat'](y=Math.min(h=x/60|0,m=x%60))+"'"[r](h-y)+','[r](m-y)  • Great use of assignments in attribute access/function arguments. +1 Mar 2, 2017 at 1:48 # Perl 6, 1031019897 69 bytes $_=get;say ";"x min($!=($_-$_%60)/60,$_=$_%60)~"'"x$!-$_~","x$_-$!;  Outputs several arrays, but fuck it, enjoy. As usual, any golfing oppertunities are appericated. Edit: -2 bytes: got brave and removed some casts. Edit2: -3 bytes by removing the arrays. Edit3: -1 byte to print in right format, using "lambdas" and removing parantheses. Edit4: (sorry guys) abusing that hours - minutes should return 0 and the opposite. Removed if statements. Then removing brackets, then realising i didnt need the lambda at all. -28 bytes :) Woah im getting better at this. # C, 141 bytes main(h,m){scanf("%d",&m);h=(m/60)%24;m%=60;while(h||m){if(h&&m){printf(";");h--;m--;}else if(h&&!m){printf("'");h--;}else{printf(",");m--;}}}  • I think you could save a few bytes by using h>0||m>0. Then you need to h--;m--; only once in every iteration and the {} for if/else would get obsolete. Dec 23, 2015 at 8:57 • You can also save a few bytes on your second conditional: instead of else if(h&&!m) you can just have else if(h) Dec 23, 2015 at 19:57 • And finally try to use the ternary operator, it will save you from using "long" words like if and else. Dec 23, 2015 at 21:14 • Consider refactoring as a function that takes the input as an int parameter - that should at least save you the scanf(). Dec 25, 2015 at 0:57 • I don't think the %24 is necessary - max input is 23:59. Dec 25, 2015 at 0:58 # Gema, 119 characters <D>=@set{h;@div{$0;60}}@set{m;@mod{$0;60}}@repeat{@cmpn{$h;$m;$h;$h;$m};\;}@repeat{@sub{$h;$m};'}@repeat{@sub{$m;$h};,}


Sample run:

bash-4.3$gema '<D>=@set{h;@div{$0;60}}@set{m;@mod{$0;60}}@repeat{@cmpn{$h;$m;$h;$h;$m};\;}@repeat{@sub{$h;$m};}@repeat{@sub{$m;$h};,}' <<< '252'
;;;;,,,,,,,,


## Matlab: 89 bytes

i=input('');m=mod(i,60);h=(i-m)/60;[repmat(';',1,min(h,m)),repmat(39+5*(m>h),1,abs(h-m))]


Test:

310
ans =
;;;;;,,,,,


# SmileBASIC, 59 bytes

INPUT M
H%=M/60M=M-H%*60?";"*MIN(H%,M);",'"[M<H%]*ABS(H%-M)


Explained:

INPUT MINUTES 'input
HOURS=MINUTES DIV 60 'separate the hours and minutes
MINUTES=MINUTES MOD 60
PRINT ";"*MIN(HOURS,MINUTES); 'print ;s for all positions with both
PRINT ",'"[MINUTES<HOURS]*ABS(HOURS-MINUTES) 'print extra ' or ,


It looks pretty terrible, since the bottom part of ; is not even the same as , in SmileBASIC's font

# PHP, 81 bytes

some more solutions:

echo($r=str_repeat)(";",min($h=$argn/60,$m=$argn%60)),$r(","[$h>$m],abs($h-$m));
// or
echo($p=str_pad)($p("",min($h=$argn/60,$m=$argn%60),";"),max($h,$m),","[$h>$m]);


Run with echo <time> | php -R '<code>'.

<?=($r=str_repeat)(";",min($h=($_=1439)/60,$m=$_%60)),$r(","[$h>$m],abs($h-$m));
// or
<?=($r=str_repeat)(";",min($h=.1/6*$_=1439,$m=$_%60)),$r(","[$h>$m],abs($h-$m));
// or
<?=str_pad(str_pad("",min($h=($_=1439)/60,$m=$_%60),";"),max($h,$m),","[$h>$m]);


Replace 1439 with input, save to file, run.

# Ruby, 50 characters

->t{(?;*h=t/60)[0,m=t%60]+",',"[0<=>m-=h]*m.abs}


Thanks to:

• G B for
• reminding me that I can't take more characters from a string than it has (-1 character)
• reorganizing my calculation (-1 character)

Waited so long to use Numeric.divmod, just to realize that its horribly long.

Sample run:

2.1.5 :001 > puts ->t{(?;*h=t/60)[0,m=t%60]+",',"[0<=>m-=h]*m.abs}[252]
;;;;,,,,,,,,

• Save 1 character by truncating the string instead of using min: (?;*h=t/60)[0,m=t%60]
– G B
Mar 2, 2017 at 12:23
• And another byte by subtracting h from m: ",',"[0<=>m-=h]*m.abs
– G B
Mar 2, 2017 at 12:40

# 05AB1E, 25 bytes

60‰vy„'.Nè×}‚.BøJ„'.';:ðK


Try it online!

60‰vy„'.Nè×} can definitely be shortened, I just couldn't figure it out, and doubt I'll be able to shave off 7 bytes to win with this approach unless there's a vectored version of ×.

Example (With input equal to 63):

60‰                       # Divmod by 60.
# STACK: [[1,3]]
vy      }              # For each element (probably don't need the loop)...
# STACK: []
„'.Nè×               # Push n apostrophe's for hours, periods for minutes.
# STACK: ["'","..."]
‚             # Group a and b.
# STACK: [["'","..."]]
.B           # Boxify.
# STACK: [["'  ","..."]]
ø          # Zip it (Transpose).
# STACK: [["'."," ."," ."]
J         # Join stack.
# STACK: ["'. . ."]
„'.';:   # Replace runs of "'." with ";".
# STACK: ["; . ."]
ðK # Remove all spaces.
# OUTPUT: ;..


D60÷''×s60%'.×‚.BøJ„'.';:ðK was my original version, but that's even MORE costly than divmod.

60‰WDµ';ˆ¼}-¬0Qi'.ë''}Z×¯ìJ yet another method I tried...

# dc, 95 bytes

[60~sdsp39sj]sd[60~spsd44sj]se?ddd60~<d60~!<e[59Plp1-spld1-dsd0<y]syld0<y[ljPlp1-dsp0<y]sylp0<y


Try it online!

# Java 8, 10199 86 bytes

n->{String r="";for(int m=n%60,h=n/60;h>0|m>0;r+=h--*m-->0?";":h<0?",":"'");return r;}


Explanation:

Try it here.

n->{                      // Method with integer parameter and String return-type
String r="";            //  Result-String (starting empty)
for(int m=n%60,h=n/60;  //   Get the minutes and hours from the input integer
h>0|m>0;            //   Loop as long as either the hours or minutes is above 0
r+=                   //   Append the result-String with:
h--*m-->0?         //    If both hours and minutes are above 0
//    (and decrease both after this check):
";"               //     Use ";"
:h<0?              //    Else-if only minutes is above 0 (hours is below 0)
","               //     Use ","
:                  //    Else:
"'"               //     Use "'"
);                      //  End loop
return r;               //  Return the result
}                         // End of method


# ///, 49 bytes

/x/1111111111//xxxxxx/o//oo1/o1o//o1/;//o/'//1/,/


Try it online!

The first two substitutions, /x/1111111111//xxxxxx/o/, replace sequences of 60 1s with an o.

/oo1/o1o/ interweaves the 1s into the os, which are next to each other. Ex. oooooo1111111111 -> o1o1o1o1o1o11111 This pairs each o, which is one hour, with one 1, which is minute. This also pushes the 1s to the left, so whichever one is greater is left at the right.

o1/;/ replaces each pair with a ;

/o/'/ /1/1/ and this converts the leftovers to :s or 's

# Jelly, 13 bytes

d60Ø½ẋ"Sị“',;


Try it online!

## Explanation

d60Ø½ẋ"Sị“',;   Main monadic link
d60             Divmod by 60
"         Zipmap
Ø½             [1, 2]
with that
ẋ            using the “repeat n times” operator
S        Sum
ị       Index into
“',;   "',;"
`