# Clock angle problem in Go

In the Clock angle problem in Java post I shared explanation and detailed solution to the clock angle problem. I provided Java implementation over. In this post, I am sharing the similar solution in Go . I am not going to present the problem and the approach to the solution as it is common to any programming language. I would recommend you read through the post as mentioned earlier for better understanding.

## Implementation in Go

I created a package called clock and put the library code in clock.go file. Please note that the package name is irrelevant and you can call it whatever is best for you. That package has three methods:

• `Overlaps` returns a slice of Time objects where the minute hand overlaps hour hand.
• `AngleMinutesToHours` returns angle from the minute to the hour hand. It panics if the given hours or minutes value is invalid.
• `AngleHoursToMinutes` returns angle from the hour to the minute hand. It panics if the given hours or minutes value is invalid.
``````package clock

import (
"math"
)

const (
minHour = 0
maxHour = 24
minMin  = 0
maxMin  = 59

fullAngle = 360

hourAngle        = fullAngle / 12.0
minuteAngle      = fullAngle / 60.0
minuteDeltaAngle = minuteAngle / 60
hourDeltaAngle   = hourAngle / 60.0
overlapConst     = 30.0 / 5.5
)

// Time struct representing time
type Time struct {
Hour, Min, Sec int
}

// Overlaps returns a slice of times where the minute hand overlaps hour hand
func Overlaps() []Time {
times := make([]Time, 0, 12)

for h := 0; h < 12; h++ {
m, s := math.Modf(overlapConst * float64(h))
min := int(m)
sec := int(math.Round(s * 60))

if sec == 60 {
continue
}

times = append(times, Time{h, min, sec})
}

return times
}

// AngleMinutesToHours returns angle from the minute to the hour hand
func AngleMinutesToHours(h, m, s int) int {
if h < minHour || h > maxHour || m < minMin || m > maxMin {
panic("Invalid hours or minutes value")
}

h = h % 12

ha := float64(h) * hourAngle + hourDeltaAngle * float64(m)
ma := float64(m) * minuteAngle + minuteDeltaAngle * float64(s)

a := int(ha - ma)

if a < 0 {
a = fullAngle + a
}

return a
}

// AngleHoursToMinutes returns angle from the hour to the minute hand
func AngleHoursToMinutes(h, m, s int) int {
return fullAngle - AngleMinutesToHours(h, m, s)
}
``````

You can call your package from your main program. In the following example, I call `clock.AngleMinutesToHours(int, int, int)` function with `1:50` time and I print out all values from the `clock.Overlaps()` functions.

``````package main

import (
"clock"
"fmt"
)

func main() {
fmt.Println(clock.AngleMinutesToHours(1, 50, 0))
for _, time := range clock.Overlaps() {
fmt.Printf("Hour: %2d, Min: %.2d, Sec: %.2d\n", time.Hour, time.Min, time.Sec)
}
}
``````

We get `115` value as an angle for `1:50` and a list of hours, minutes and seconds where the minute hand overlaps the hour hand.

``````Hour:  0, Min: 00, Sec: 00
Hour:  1, Min: 05, Sec: 27
Hour:  2, Min: 10, Sec: 55
Hour:  3, Min: 16, Sec: 22
Hour:  4, Min: 21, Sec: 49
Hour:  5, Min: 27, Sec: 16
Hour:  6, Min: 32, Sec: 44
Hour:  7, Min: 38, Sec: 11
Hour:  8, Min: 43, Sec: 38
Hour:  9, Min: 49, Sec: 05
Hour: 10, Min: 54, Sec: 33
``````

## Testing

This post is based on an interview question. An interviewer tries to find out about your ability to develop in Go as much as possible. In many cases, you may be asked to provide a supporting testing mechanism. In Go, test functions go to files whose names end with `_test.go`. A test function begins with `Test` and accepts `*testing.T` argument.

I created `clock_test.go` file in the `clock` package directory.

``````package clock

import (
"testing"
)

func TestOverlaps(t *testing.T) {
times := Overlaps()

if len(times) != 11 {
t.Errorf("Overlaps should return 11 records, got: %d", len(times))
}
}

func TestInvalidInput(t *testing.T) {

f := func(f func(int, int, int) int, h, m int) {
defer func() {
if r := recover(); r == nil {
t.Errorf("Function should panic for hours: %d, minutes: %d", h, m)
}
}()

f(h, m, 0)
}

f(AngleMinutesToHours, -1, 30)
f(AngleMinutesToHours, 25, 30)
f(AngleMinutesToHours, 10, -1)
f(AngleMinutesToHours, 10, 60)

f(AngleHoursToMinutes, -1, 30)
f(AngleHoursToMinutes, 25, 30)
f(AngleHoursToMinutes, 10, -1)
f(AngleHoursToMinutes, 10, 60)
}

func TestAngles(t *testing.T) {
tests := []struct {
h, m, r1, r2 int
}{
{0, 0, 0, 0},
{12, 0, 0, 0},
{1, 50, 115, 245},
{13, 50, 115, 245},
{3, 0, 90, 270},
{15, 0, 90, 270},
{6, 0, 180, 180},
{18, 0, 180, 180},
{9, 0, 270, 90},
{21, 0, 270, 90},
}

for _, test := range tests {
if r := AngleMinutesToHours(test.h, test.m, 0); r != test.r1 {
t.Errorf("AngleMinutesToHours failed, got: %d, want: %d", r, test.r1)
}

if r := AngleHoursToMinutes(test.h, test.m, 0); r != test.r2 {
t.Errorf("AngleHoursToMinutes failed, got: %d, want: %d", r, test.r2)
}
}
}
``````

This class is not very complicated, and it should not be.

In order to run the test, you call `go test` command. You can also add`-cover` flag to find out code coverage. Let’s call `go test -cover` from our clock package directory. The output is very similar to the following one. You can see that we passed all tests and we have 100% code coverage, which is what we expected.

``````PASS
coverage: 100.0% of statements
ok      clock   0.006s
``````

Couple of extra things to mention. Even though the test class is not very complicated, it has some interesting features. The `TestAngles` function uses anonymous struct. Usage of anonymous structs is a pretty clean and common approach for holding test data and their expected results. Another one is in `TestInvalidInput` function. It presents an approach of testing panic by using the recover function.

## Benchmarking

Similarly to the testing class, you may be asked to measure the performance of your package. Go provides a benchmarking mechanism that measures the performance of your program on a fixed workload.

In Go, benchmark functions are very similar to the test functions. The only difference is that they are with the `Benchmark` prefix and they accept `*testing.B` parameter.

In the example below I created three benchmark functions for my key methods.

``````func BenchmarkOverlaps(b *testing.B) {
// run the Fib function b.N times
for n := 0; n < b.N; n++ {
Overlaps()
}
}

func BenchmarkAngleMinutesToHours(b *testing.B) {
// run the Fib function b.N times
for n := 0; n < b.N; n++ {
AngleMinutesToHours(1, 50, 0)
}
}

func BenchmarkAngleHoursToMinutes(b *testing.B) {
// run the Fib function b.N times
for n := 0; n < b.N; n++ {
AngleHoursToMinutes(1, 50, 0)
}
}
``````

All I need to do now is to add these benchmark functions to my `clock_test.go` file and run `go test -bench=.` command from my `clock` package directory. The Go test command calls all your `Benchmark*` functions. You should get the results that look very similar to the following ones.

``````oos: darwin
goarch: amd64
pkg: clock
BenchmarkOverlaps-8                     10000000               198 ns/op
BenchmarkAngleMinutesToHours-8          2000000000            0.33 ns/op
BenchmarkAngleHoursToMinutes-8          200000000             9.63 ns/op
PASS
ok      clock   5.770s
``````

Note that it is doubtful that your benchmark results will be the same. The benchmark results depend on the operating system, CPU architecture and so on. You may also run individual benchmark functions by specifying their names (without the `Benchmark` prefix) in the bench parameter e.g. `go test -bench=Overlaps` for `BenchmarkOverlaps` or `go test -bench=Angle` for `BenchmarkAngleMinutesToHours` and `BenchmarkAngleHoursToMinutes`.

## Conclusion

I presented this Go solution purely for learning purposes. You should go through it and do as experiments with different values or parameters as you can. Learning different solutions by heart is never a good idea. However, learning by practice and exercise is the best approach to master any programming language.

I hope that this post will help you to improve your skills and hopefully give you a change of finding a better job or getting a better position.

Happy coding.