40
\$\begingroup\$

Given the time in 24 hour format (2359 = 11:59pm) return the angle between the minute and hour hands on a standard clock (on the face plane, so don't just output 0).

Angles are to be returned in the unit of your choice, should be the smallest possible, and should be a positive number (negative angle converted to a positive value), i.e. you will never have an answer greater than 180 degrees or pi radians.

Some examples to check against (in degrees)

  • 0000 = 0.0
  • 0010 = 55.0
  • 0020 = 110.0
  • 0030 = 165.0
  • 0040 = 140.0
  • 0050 = 85.0
  • 0150 = 115.0
  • 0240 = 160.0
  • 0725 = 72.5
  • 1020 = 170.0
  • 1350 = 115.0
  • 1725 = 12.5

Note: There are a few that have rounding errors, I'm not sure how that should be handled; if we should force consistency across all values.

\$\endgroup\$
14
  • 2
    \$\begingroup\$ The clockwise angle, or the smallest of the two? \$\endgroup\$ Jan 27, 2011 at 22:18
  • 1
    \$\begingroup\$ @SimpleCoder: Smallest, as the question says. \$\endgroup\$ Jan 27, 2011 at 22:21
  • 3
    \$\begingroup\$ You should include some correct input/output examples including "difficult" input like 0001, 0633, etc... I notice that many answers actually produce incorrect results. \$\endgroup\$ Jan 28, 2011 at 6:21
  • 1
    \$\begingroup\$ @Nakilon: Can't speak for anyone else, but in my case {1} I missed the tagging (need to establish new habits for this place), {2} golfing is why I came here, and {3} it's kind of simple for anything else, isn't it? \$\endgroup\$ Jan 28, 2011 at 18:44
  • 1
    \$\begingroup\$ Oh boy, after 5 years my SO notification bar has been going crazy. What a surprising necro, haha. I'll check back in a few days to see if anyone can confirm the APL answer is correct (I'm traveling). I haven't been on this site for ages, but it would sure be nice to be able to mark golfs by language since this has since becoming golfing. \$\endgroup\$ Jan 14, 2016 at 23:45

21 Answers 21

15
\$\begingroup\$

Haskell - 78 characters

q[h,i,m,n]=abs$((600*h+60*i-110*m-11*n-312)`mod`720)-360
c s=q$map fromEnum s

Note: My "unit of choice" is the "half-degree", of which there are 720 to the circle. With these units, the answer to the problem is always integral! :-)

Ex.:

> map c $ words "0000 0001 0010 0630 0633 2325 2345 2355 2359"
[0,11,110,30,3,335,165,55,11]
> map c $ words "0930 1845 0315 1742 2359"
[210,135,15,162,11]
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Half-a-degree's. Nice. \$\endgroup\$ Jan 28, 2011 at 16:16
  • 1
    \$\begingroup\$ c s=q$map fromEnum s can be c=q.map fromEnum. ( ... )`mod`720 can be mod( ... )720. \$\endgroup\$
    – Laikoni
    Feb 1, 2018 at 13:38
12
\$\begingroup\$

Golfscript, 42 bytes

2/~~\~60*+55*3600%.3600\-]{}$~;.10/'.'@10%

Outputs whole-a-degrees in float format.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ +1 Great program! You can save a char by assigning 3600 to a variable and reusing that. \$\endgroup\$ Aug 27, 2012 at 7:11
  • 1
    \$\begingroup\$ @w0lf ah good trick. I dont know any golf script, but thats bound to save like 2-5 bytes. \$\endgroup\$ Jan 10, 2016 at 19:54
6
\$\begingroup\$

Perl, 58 characters

Perl is fun

perl -nlE "/(..)(..)/;$r=abs$1%12*30-5.5*$2;say+($r,360-$r)[$r>180]"
\$\endgroup\$
6
\$\begingroup\$

TI-BASIC, 22 bytes

expr(Ans
sin⁻¹(sin(πfPart(11/6!(Ans-40int(sub(Ans

My unit is the "πth of a revolution", equal to 2 radians. The TI-83+ was introduced in 1996, making it much older than this challenge and thus eligible.

First we evaluate the string using expr(, then:

                                 sub(Ans   input/100. Don't ask why.
                             int(sub(Ans   Number of hours
                           40              Times 40
                       Ans-                Subtract from input. This converts to minutes.
                 11/6!(                    Multiply by 11/720 since 720/11 is the period.
           fPart(                          Take fractional part
sin⁻¹(sin(π                                Map [0,½] to [0,π/2] and [½,1] to [π/2,0].

All test cases have been verified.

\$\endgroup\$
3
  • \$\begingroup\$ wait what!? sub( is a string manipulation function... Yeah, I'm asking :P \$\endgroup\$ Jan 15, 2016 at 3:55
  • 1
    \$\begingroup\$ sub( is a bit strange: it's the one only overloaded TI-BASIC command. When called with a number or list as its only argument, it calculates x/100, vectorized on lists. See here. \$\endgroup\$
    – lirtosiast
    Jan 15, 2016 at 4:26
  • 1
    \$\begingroup\$ @DanMcGrath I've revised my answer to take input as a string. If an integer is acceptable, I'll revert. \$\endgroup\$
    – lirtosiast
    Jan 15, 2016 at 17:10
6
\$\begingroup\$

ES6, 52 50 bytes

t=>(t=(t-t.match`..`*40)*11%720,(t>360?720-t:t)/2)

Input string, output in degrees. If half degrees is acceptable, 46 bytes:

t=>(t=(t-t.match`..`*40)*11%720,t>360?720-t:t)

Edit: Saved 2 bytes by using a template string parameter to match.

\$\endgroup\$
4
\$\begingroup\$

Ruby 1.9.2p136 : 78 74

def a(t)m=t[2,2].to_f
180-((m*6-(m/60+t[0,2].to_f%12)*30).abs-180).abs
end

Sample output:

["0000", "0010", "0020", "0030", "0040", 
  "0050", "0150", "0240", "0725", "1020", 
  "1350", "1725"].each do |time|
  puts "#{time} = #{a(time)}"
end
# Output
0000 = 0.0
0010 = 55.0
0020 = 110.0
0030 = 165.0
0040 = 140.0
0050 = 85.0
0150 = 115.0
0240 = 160.0
0725 = 72.5
1020 = 170.0
1350 = 115.0
1725 = 12.5
\$\endgroup\$
3
  • 1
    \$\begingroup\$ You output has the hour hand fixed on the hour marks rather than sweeping during the hour. Most answers have been assuming a uniform sweep for the hour hand. \$\endgroup\$ Jan 28, 2011 at 16:32
  • \$\begingroup\$ Yep, and it also doesn't work if the hour hand is at say 1 and the minute hand is at 11. I fell asleep before fixing it... \$\endgroup\$
    – Mike Bethany
    Jan 28, 2011 at 20:01
  • \$\begingroup\$ Fixed and updated. \$\endgroup\$
    – Mike Bethany
    Jan 29, 2011 at 2:10
4
\$\begingroup\$

Perl, 61 characters:

sub f{$a=abs(int($_[0]/200)-($_[0]%60)/5);($a>6?12-$a:$a)*30}
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Your answer is wrong: 1. It generates wrong results for 1059, 1058, etc. 2. 0020 should be 110 degrees, 0030 should be 165, 0040 should be 140, and 0050 should be 85. (The hour hand moves 30 degree every hour---thus, it moves half a degree every minute.) \$\endgroup\$ Jan 27, 2011 at 22:46
4
\$\begingroup\$

C99, 86 78 bytes

My units are twelfths of revolutions (so 3 corresponds to 90°)

#include<math.h>
float f(int t){return fabs(remainder((t+t%100/1.5)*.11,12));}

Equivalently, in C++14, for 76 bytes:

#include<cmath>
auto f(int t){return fabs(remainder((t+t%100/1.5)*.11,12));}

BSD and SVID platforms have remd as an alias for remainder (to save 5 more), but I'm sticking with standard C and C++.

Explanation

We convert sexagesimal seconds to centihours by adding t%100/1.5 (so 0030 becomes 0050 etc), and divide by 100 to get hours. Coincidence of hands occurs 11 times every 12 hours, so multiply by 11 and divide by 12; we take the remainder in the range [-6,+6], and return its absolute value.

Test program

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char**argv)
{
    int i;
    for (i = 1;  i < argc;  ++i)
        printf("%4s: %f\n", argv[i], f(atoi(argv[i])));
    return 0;
}

Test output:

A minimum around 12:00:

1150: 1.833333
1151: 1.650000
1152: 1.466667
1153: 1.283333
1154: 1.100000
1155: 0.916667
1156: 0.733333
1157: 0.550000
1158: 0.366667
1159: 0.183333
1200: 0.000000
1201: 0.183333
1202: 0.366667
1203: 0.550000
1204: 0.733333
1205: 0.916667
1206: 1.100000
1207: 1.283333
1208: 1.466667
1209: 1.650000
1210: 1.833333

And a maximum around 6:00:

0555: 5.083333
0556: 5.266667
0557: 5.450000
0558: 5.633333
0559: 5.816667
0600: 6.000000
0601: 5.816667
0602: 5.633333
0603: 5.450000
0604: 5.266667
0605: 5.083333
\$\endgroup\$
1
4
\$\begingroup\$

Dyalog APL, 34 32 27 25 characters

Full program. Prompts for 4-character string from stdin. Prints radians to stdout.

¯2○2○○360÷⍨11×60⊥⍎¨↓2 2⍴⎕

Try it online!

The angle changes linearly with the time, going through 22×360° every 1440 minutes, or 5.5°/min.

Method:

  1. Take input: 

  2. Make into 2-by-2 table: 2 2⍴

  3. Split into rows: 

  4. Evaluate each: ⍎¨

  5. Convert to minutes: 60⊥

  6. Convert to degrees and then to radians (5.5t × π/180 = 11t × π/360): ○360÷⍨11×

  7. arccos cos to invert after π/2: ¯2○2○

Test cases can be verified by converting the result into degrees:

      angle←  {¯2○2○○360÷⍨11×60⊥⍎¨↓2 2⍴⍵}
      rads2degs←{180×⍵÷○1}

      rads2degs angle ¨ '0000' '0010' '0020' '0030' '0040' '0050' '0150' '0240' '0725' '1020' '1350' '1725'
0 55 110 165 140 85 115 160 72.5 170 115 12.5

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Perl, 91 chars

#!perl -n
($h,$m)=/(..)(..)/;$h=$h%12+$m/60;$h=abs($h*30-$m*6);printf'%f
',$h>180?360-$h:$h
\$\endgroup\$
3
\$\begingroup\$

PHP, 80 Characters

<?=($i=$argv[1])&&($n=abs(($i[0].$i[1])%12*30-($i[2].$i[3])*5.5))>180?360-$n:$n;

Can be run from CLI php /script_name input

Explanation:

<?=                           // output result to console
    ($i = $argv[1]) && (      // $argv is an array containing CLI parameters (0: script name, 1: first parameter, etc.)
        $n = abs(             // absolute value to deal with negative numbers
            ($i[0] . $i[1])   // get hours - the first two characters from the input (0 and 1)
                % 12 * 30     // modulus 12 to deal with PM hours (13-23) multiplied by 360/12 = 30 degrees
            - ($i[2] . $i[3]) // get minutes - the subsequent characters from the input (2 and 3)
                * 5.5)        // multiply minutes by 5.5 (1 minute is 360/60 = 6 degrees
                              // and the hour hand moves every minute by 30/60 = 0.5 degrees which we subtract)
        ) > 180               // compare obtained result to 180
    ? 360 - $n                // if the result is greater subtract it from 360
    : $n;                     // if it's less - output as it is

Test cases (input output)

0000 0
0010 55
0155 87.5
0240 160
1234 173
2155 32.5
2222 179
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Have I missed something? This works correctly for all examples given in the question, so can't imagine why was downvoted. \$\endgroup\$
    – manatwork
    Jan 11, 2016 at 13:07
  • 1
    \$\begingroup\$ Welcome to Programming Puzzles & Code Golf! Sorry your first post got downvoted; I see no reason why it should be. Though if you could add some explanation of the code, that would be nice. :) \$\endgroup\$
    – Alex A.
    Jan 11, 2016 at 20:06
  • \$\begingroup\$ Thanks guys. Added code explanation. Maybe someone's angry that we've resurrected a five year old thread :) \$\endgroup\$ Jan 11, 2016 at 21:09
3
\$\begingroup\$

Matlab/Octave, 56 bytes

An anonymous function accepting a string, output is in degrees.

@(i)180-abs(mod((i-48)*[600;60;10;1],720/11)-360/11)*5.5
\$\endgroup\$
3
\$\begingroup\$

Python, 82 bytes

def a(t):
    o=abs(30*(int(t[:1])%12)-5.5*int(t[2:]));return o if o<=180 else 360-o

With some help from the python golfing question I've brought it down to 76:

def a(t):
    o=abs(30*(int(t[:1])%12)-5.5*int(t[2:]));return [o,360-o][o>180]
\$\endgroup\$
1
  • \$\begingroup\$ no need for a space itn return [. You should convert to a lambda function anyhow if you can (for golfing) \$\endgroup\$
    – gnibbler
    Jan 28, 2011 at 1:24
2
\$\begingroup\$

c99 -- 204 necessary characters (keeps getting worse as I fix bugs)

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(){char b[5]={0};fgets(b,5,stdin);int a,h,m=atoi(b+2);b[2]=0;
h=(atoi(b)*60+m)%720;m*=12;a=abs((h-m)%720);a=a>360?720-a:a;printf("%i\n",a);}

Discussion:

The problem turns out to be harder than it looks. The critical issue is what is meant by "smallest positive angle". I've interpreted that the mean a value between [0,180] degrees inclusive (because the problem does not specify which hand to start from when measuring).

To validate this behavior look for places when the hands pass the straight-apart position (such as around 00:33-00:35), and places where they cross-over as around 06:33.

I've also chosen to have a steadily sweeping hour hand, as most modern clocks seem to use that method.

I've adopted MtnViewMark clever trick of using half-degrees as the base unit.

I've suffered the usual problem with c: the preprocessor commands to get the libraries eat up a lot of characters.

Readable and commented:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(){
  char b[5]={0};
  fgets(b,5,stdin); /* assumes single byte charaters */
/*   printf("'%s'\n",b); */
  int a,h,m=atoi(b+2); /* minutes */
  b[2]=0;
  h=(atoi(b)*60+m)%720;  /* hour had position in hald-degrees */
  m*=12;                 /* minute hand position in half degrees */
/*   printf("%3i\t%3i\n",h,m); */
/*   printf("%i\n", h-m ); */
/*   printf("%i\n",(h-m)%720 ); */
  a=abs((h-m)%720);
/*   printf("%i\n",   a ); */
  a=a>360?720-a:a;
  printf("%i\n",a);
}

Validation:

$gcc -c99 golf_clock_angle.c
$wc golf_clock_angle.c
  5  11 206 golf_clock_angle.c
$!for
for t in $(cat clock_test_times.txt); do echo $t $(echo $t|./a.out); done
0000 0
0001 11
0002 22
0010 110
0015 165
0030 330
0033 357
0034 346
0035 335
0045 225
0630 30
0633 3
0634 14
2324 324
2325 335
2355 55
2359 11
\$\endgroup\$
5
  • \$\begingroup\$ Your answers are way off. For instance at 0010 the minute hand will be at 60 degrees and the hour hand will be at 5 degrees. There are 55 degrees between them. In fact a lot of your angles look doubled. \$\endgroup\$
    – Mike Bethany
    Jan 29, 2011 at 2:29
  • \$\begingroup\$ @Mike: Note the units. I've adopted MntViewMark's convention of expressing answers in half-degrees. \$\endgroup\$ Jan 29, 2011 at 3:20
  • \$\begingroup\$ Ah, seems like cheating to me... let me see if I can abuse it too. ;) \$\endgroup\$
    – Mike Bethany
    Jan 29, 2011 at 3:55
  • 1
    \$\begingroup\$ Says "Angles are to be returned in the unit of your choice"... ;-) \$\endgroup\$ Feb 15, 2011 at 19:29
  • 1
    \$\begingroup\$ @MntViewMark: Yep. But I'll bet Dan was thinking "degrees or radians" when he wrote that. \$\endgroup\$ Feb 15, 2011 at 19:51
2
\$\begingroup\$

Mathematica

Grid@Prepend[
Table[{Row[{Quotient[x, 60] /. {0 -> 12}, ":", If[Mod[x, 60] < 10, "0", ""], Mod[x, 60]}],
x, N[x/2, 3], Mod[6 x, 360], 
IntegerPart[Min[Abs[x/2 - Mod[6 x, 360]], 360 - Abs[x/2 - Mod[6 x, 360]]]]}, 
{x, 0, 12*60}], {"time", "elapsed min", "hourhand deg", "min deg", "diff deg"}]

Partial output in table

table

Graphs

Plot[{ x/2, Mod[6 x, 360], Min[Abs[x/2 - Mod[6 x, 360]], 360 - Abs[x/2 - Mod[6 x, 360]]]}, {x, 0, 12*60},PlotStyle -> {Green, Blue, {Thick, Red}},AxesLabel -> {"time (hs)", "degrees"},GridLinesStyle -> Directive[Dotted, Gray],Ticks -> {Table[{60 k, k}, {k, 0, 12}], Table[30 k, {k, 0, 12}]},GridLines -> {Table[60 k, {k, 0, 12}], None}]

The green line shows the angle of the hour hand, as measured in degrees from 12 o'clock, clockwise. The blue line shows the corresponding angle for the minute hand. The red curve shows the difference between the minute and hour hands in degrees; it always uses the interior angle.

graphs

\$\endgroup\$
1
  • \$\begingroup\$ It does not seem like an attempt to golf the code has been made, which makes the answer in its current form invalid. \$\endgroup\$
    – Laikoni
    Feb 1, 2018 at 13:44
2
\$\begingroup\$

C++, 175 174 166 156 Characters

#include <iostream>
#include <cmath>
int main(){int m,h;std::cin>>h;m=h%100;h=(h-m)/100;h=h>11?h=h-12:h;h=std::abs(h*60-m*11);std::cout<<std::min(720-h,h);}

Using "half degree's" as my unit of choice :D

Try it Online!

\$\endgroup\$
2
\$\begingroup\$

C# (.NET Core), 87 bytes

t=>{var i=int.Parse(t);double d=i/100%12*30-i%100*5.5,r=d<0?-d:d;return r>180?360-r:r;}

Try it online!

I'm sure there are possible improvements that I have missed.

DeGolfed

t=>{
    var i = int.Parse(t);
    // The hour angles minus the minute angles
    double d = i / 100 % 12 * 30 -
               i % 100 * 5.5,
    // account for this possibly being a negative angle
           r = d < 0? -d : d;

    // Get the smaller of the two possible rotational angles
    return r > 180? 360-r : r;
}
\$\endgroup\$
2
\$\begingroup\$

Python, 106 bytes

Non-golf solution:

def angle_24hr(time_str):
    hour, minute = int(time_str[0:1]) % 12, int(time_str[2:3]) % 60
    angle_dist = lambda a, b: ((a + (180 - b)) % 360) - 180
    return angle_dist(((hour * 30) + (minute * 0.5)), minute * 6) * 10

In a more obscure/obfuscated form (admittedly, one of my first code golfs):

ad=lambda a,b:((a-b+180)%360)-180;x=int;ag=lambda t:10*ad((x(t[0:1])%12)*60+x(t[2:3]),(x(t[2:3]*12)%60)*6)

(what's the point of obfuscating Python?)

If it's necessary for the angles to be purely positive you can remove the -180 term.

\$\endgroup\$
5
  • \$\begingroup\$ Your answer is wrong: 0020 should be 110 degrees, 0030 should be 165, 0040 should be 140, and 0050 should be 85. (The hour hand moves 30 degree every hour---thus, it moves half a degree every minute.) \$\endgroup\$ Jan 27, 2011 at 22:42
  • \$\begingroup\$ @Chris, why 110 degrees for 0020? Am I missing something: hour hand is at 0, minute hand is at 20*6 = 120...? \$\endgroup\$
    – Thomas O
    Jan 27, 2011 at 22:44
  • \$\begingroup\$ The hour hand is not at 0 when the minute hand is at 20. It's at one-third between 12 and 1. \$\endgroup\$ Jan 27, 2011 at 22:47
  • \$\begingroup\$ @Chris Of course, now it seems obvious to me. Back in a sec with fixed code. \$\endgroup\$
    – Thomas O
    Jan 27, 2011 at 22:48
  • 1
    \$\begingroup\$ Depends on your clock. My clock only moves the hour hand on full hours. Since it wasn't specified in the question it wouldn't make much sense to do it the hard way would it? OK... I'll just admit it... I screwed up to... doh! \$\endgroup\$
    – Mike Bethany
    Jan 28, 2011 at 11:58
1
\$\begingroup\$

JavaScript (ES6), 75 bytes

x=>Math.min(x=((x=x.match(/\d\d/g))[0]*60+x[1]*1)*5.5%360,360-x).toFixed(1)

This question needed a JavaScript solution.

\$\endgroup\$
0
\$\begingroup\$

05AB1E, 23 bytes

2ôć12%30*s11;*αD360α)˜ß

Outputs degrees like the challenge description.

Port of @Juan's Python answer.

Try it online or verify all test cases.

Explanation:

2ô                  # Split the (implicit) input in pieces of 2
                    #  i.e. "0150" → ['01','50']
  ć                 # Head extracted
                    #  i.e. ['01','50'] → ['50'] and '01' are pushed to the stack
   12%              # Take the hours modulo 12
      30*           # Multiplied by 30
                    #  i.e. '01' → 30
  s                 # Swap so the minutes are now at the top of the stack
   11;*             # And multiple it by 5.5
                    #  i.e. ['50'] → [275.0]
       α            # Calculate the absolute difference between the two values
                    #  30 and [275.0] → [245.0]
        D           # Duplicate this value
         360α       # Calculate the absolute difference between this value and 360
                    #  i.e. [245.0] → [115.0]
             )      # Wrap the entire stack to a list
                    #  i.e. [245.0] and [115.0] → [[245.0],[115.0]]
              ˜     # Flatten this list (necessary due to the head extracted)
                    #  i.e. [[245.0],[115.0]] → [245.0,115.0]
               ß    # And take the smallest value of the two (output implicitly)
                    #  i.e. [245.0,115.0] → 115.0
\$\endgroup\$
0
\$\begingroup\$

SmileBASIC, 60 bytes

INPUT T
A=ABS(T DIV 100*60-T MOD 100*11)?A/2+(360-A)*(A>360)
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.