Angle between the hands on a clock

36

4

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.

Dan McGrath

Posted 2011-01-27T21:56:04.557

Reputation: 959

Question was closed 2019-06-21T19:40:35.250

So I'm assuming the input is always a 4 character string? – None – 2011-01-28T04:04:04.317

That is correct @Mike – Dan McGrath – 2011-01-28T04:37:48.217

3You should include some correct input/output examples including "difficult" input like 0001, 0633, etc... I notice that many answers actually produce incorrect results. – MtnViewMark – 2011-01-28T06:21:40.437

@SimpleCoder: I think a "smallest positive" implies clockwise angle. Counterclockwise would correspond to negative angles. "Smallest" probably means "least multiple of 2*pi". – hallvabo – 2011-01-28T08:51:23.670

It appears that this wasn't originally code-golf. But now that it is, consider revising the accepted answer. – Adám – 2016-01-14T22:56:49.643

1Oh 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. – Dan McGrath – 2016-01-14T23:45:44.777

You can download a free APL interpreter from dyalog.com.

– Adám – 2016-01-15T09:16:16.583

Why do everybody golf, when it was not supposed to golf? ) – Nakilon – 2011-01-28T18:06:49.223

1@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? – dmckee --- ex-moderator kitten – 2011-01-28T18:44:26.667

A few of the example answers are incorrect and the question is poorly worded ("positive angle only" for instance). I've corrected the examples, clarified the answer, and provided some more examples to highlight possible errors. – None – 2011-01-29T02:01:55.847

2The clockwise angle, or the smallest of the two? – Chris Laplante – 2011-01-27T22:18:28.000

1@SimpleCoder: Smallest, as the question says. – Chris Jester-Young – 2011-01-27T22:21:03.007

00:10 will be 0010 or 010? – Nakilon – 2011-01-28T00:04:22.603

It will be 0010 in 24 hour time @Nakilon – Dan McGrath – 2011-01-28T00:22:03.387

Answers

15

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]

MtnViewMark

Posted 2011-01-27T21:56:04.557

Reputation: 4 779

Half-a-degree's. Nice. – dmckee --- ex-moderator kitten – 2011-01-28T16:16:31.873

c s=q$map fromEnum s can be c=q.map fromEnum. ( ... )`mod`720 can be mod( ... )720. – Laikoni – 2018-02-01T13:38:43.080

11

Golfscript, 42 bytes

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

Outputs whole-a-degrees in float format.

aaaaaaaaaaaa

Posted 2011-01-27T21:56:04.557

Reputation: 4 365

1+1 Great program! You can save a char by assigning 3600 to a variable and reusing that. – Cristian Lupascu – 2012-08-27T07:11:45.117

@w0lf ah good trick. I dont know any golf script, but thats bound to save like 2-5 bytes. – Ashwin Gupta – 2016-01-10T19:54:33.070

6

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.

Neil

Posted 2011-01-27T21:56:04.557

Reputation: 95 035

6

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.

lirtosiast

Posted 2011-01-27T21:56:04.557

Reputation: 20 331

wait what!? sub( is a string manipulation function... Yeah, I'm asking :P – Conor O'Brien – 2016-01-15T03:55:10.953

1sub( 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. – lirtosiast – 2016-01-15T04:26:46.560

1@DanMcGrath I've revised my answer to take input as a string. If an integer is acceptable, I'll revert. – lirtosiast – 2016-01-15T17:10:30.390

5

Perl, 58 characters

Perl is fun

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

chinese perl goth

Posted 2011-01-27T21:56:04.557

Reputation: 1 089

4

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

Toby Speight

Posted 2011-01-27T21:56:04.557

Reputation: 5 058

You can squeeze more bytes by declaring the function anonymous and generic, also returning via reference parameter saves bytes: https://codegolf.stackexchange.com/questions/137549/dropsort-it-like-its-hot/137854#137854

– Karl Napf – 2017-11-30T04:15:22.640

4

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!

Adám

Posted 2011-01-27T21:56:04.557

Reputation: 37 779

3

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

Mike Bethany

Posted 2011-01-27T21:56:04.557

Reputation:

1You 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. – dmckee --- ex-moderator kitten – 2011-01-28T16:32:26.473

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... – None – 2011-01-28T20:01:12.890

Fixed and updated. – None – 2011-01-29T02:10:09.270

3

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

Chris Jester-Young

Posted 2011-01-27T21:56:04.557

Reputation: 4 464

3

Perl, 61 characters:

sub f{$a=abs(int($_[0]/200)-($_[0]%60)/5);($a>6?12-$a:$a)*30}

Anon.

Posted 2011-01-27T21:56:04.557

Reputation: 1 799

1Your 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.) – Chris Jester-Young – 2011-01-27T22:46:40.970

3

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]

Juan

Posted 2011-01-27T21:56:04.557

Reputation: 2 738

no need for a space itn return [. You should convert to a lambda function anyhow if you can (for golfing) – gnibbler – 2011-01-28T01:24:11.863

3

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

flawr

Posted 2011-01-27T21:56:04.557

Reputation: 40 560

2

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.

Thomas O

Posted 2011-01-27T21:56:04.557

Reputation: 3 044

1Depends 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! – None – 2011-01-28T11:58:34.420

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.) – Chris Jester-Young – 2011-01-27T22:42:01.460

@Chris, why 110 degrees for 0020? Am I missing something: hour hand is at 0, minute hand is at 20*6 = 120...? – Thomas O – 2011-01-27T22:44:38.147

The hour hand is not at 0 when the minute hand is at 20. It's at one-third between 12 and 1. – Chris Jester-Young – 2011-01-27T22:47:34.403

@Chris Of course, now it seems obvious to me. Back in a sec with fixed code. – Thomas O – 2011-01-27T22:48:05.007

2

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

patrick

Posted 2011-01-27T21:56:04.557

Reputation: 31

2Have I missed something? This works correctly for all examples given in the question, so can't imagine why was downvoted. – manatwork – 2016-01-11T13:07:54.763

1Welcome 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. :) – Alex A. – 2016-01-11T20:06:58.057

Thanks guys. Added code explanation. Maybe someone's angry that we've resurrected a five year old thread :) – patrick – 2016-01-11T21:09:35.430

2

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

DavidC

Posted 2011-01-27T21:56:04.557

Reputation: 24 524

It does not seem like an attempt to golf the code has been made, which makes the answer in its current form invalid.

– Laikoni – 2018-02-01T13:44:03.273

1

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;
}

Ayb4btu

Posted 2011-01-27T21:56:04.557

Reputation: 541

1

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

dmckee --- ex-moderator kitten

Posted 2011-01-27T21:56:04.557

Reputation: 2 726

Says "Angles are to be returned in the unit of your choice"... ;-) – MtnViewMark – 2011-02-15T19:29:11.247

@MntViewMark: Yep. But I'll bet Dan was thinking "degrees or radians" when he wrote that. – dmckee --- ex-moderator kitten – 2011-02-15T19:51:56.863

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. – None – 2011-01-29T02:29:55.190

@Mike: Note the units. I've adopted MntViewMark's convention of expressing answers in half-degrees. – dmckee --- ex-moderator kitten – 2011-01-29T03:20:06.623

Ah, seems like cheating to me... let me see if I can abuse it too. ;) – None – 2011-01-29T03:55:54.503

1

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!

jac4e

Posted 2011-01-27T21:56:04.557

Reputation: 11

1

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.

Mwr247

Posted 2011-01-27T21:56:04.557

Reputation: 3 494

0

SmileBASIC, 60 bytes

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

12Me21

Posted 2011-01-27T21:56:04.557

Reputation: 6 110

0

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

Kevin Cruijssen

Posted 2011-01-27T21:56:04.557

Reputation: 67 575