# Programming Accurate Clock Hands

So, I recently followed a tutorial on scripting the simple hands of a clock.
However, I want to build further on the program by making the hands point accurately relative to the other hands, just like a real-life analog clock.

Here’s the current code I have for the Clock Animator:

``````public class ClockAnimator : MonoBehaviour {

private const float
hoursToDegrees = 360f / 12f,
minutesToDegrees = 360f / 60f,
secondsToDegrees = 360f / 60f;

public Transform hours, minutes, seconds;

// Update is called once per frame
void Update () {
DateTime time = DateTime.Now;
hours.localRotation = Quaternion.Euler(0f, 0f, time.Hour * -hoursToDegrees);
minutes.localRotation = Quaternion.Euler(0f, 0f, time.Minute * -minutesToDegrees);
seconds.localRotation = Quaternion.Euler(0f, 0f, time.Second * -secondsToDegrees);
}
``````

What should I do to start on this?

Thanks!

**EDIT: ** Thanks for everyone who helped with the solution!

Here’s what I got:

``````public class ClockAnimator : MonoBehaviour
{
private const float
hoursToDegrees = 360f / 12f,
minutesToDegrees = 360f / 60f,
secondsToDegrees = 360f / 60f;

public float rHours, rMinutes, rSeconds = 0;
int iHours, iMinutes, iSeconds;

public Transform hours, minutes, seconds;
public bool analog = true; // Smooth == true, Rigid TickTock == false.

public bool useCustomTime = true;
public bool activeTime = true;

public float m_timeAmplifier = 20f;
public DayCycle m_customTime = new DayCycle();
[Serializable]
public class DayCycle
{
[SerializeField]
public float m_time;

private float m_hours;
private float m_minutes;
private float m_seconds;

public float Hours { get { return Mathf.Repeat(m_time / 3600f, 24f); } }
public float Minutes { get { return Mathf.Repeat(m_time / 60f, 60f); } }
public float Seconds { get { return Mathf.Repeat(m_time, 60f); } }
public bool militaryTime = false;

{
m_time += durationInSeconds;
if (m_time > 86400) // == 60*60*24 wrap around after a day.
m_time -= 86400;
//if (m_time > 43200) //
//    m_time -= 43200;
}

public void SetTime(int aHour, int aMinute, int aSecond)
{
//if (!militaryTime)
//{

//    if (aHour > 12)
//    {
//        aHour -= 12;
//    }
//    if (aHour < 1)
//    {
//        aHour = 12;
//    }
//}
m_time = (aHour * 60f + aMinute) * 60f + aSecond;
Debug.Log("Set Time = (" + aHour + "* 60 " + "+ " + aMinute + ")" + " * 60 + " + aSecond + " = " + m_time);
}

public void SetTime(float hours, float minutes, float seconds)
{
m_hours = 0.0f;
m_minutes = 0.0f;
m_seconds = 0.0f;

}

/*[SerializeField]
private float m_hours = 7, m_minutes = 5, m_seconds = 23;
public float Hours { get { return m_hours; } set { m_hours = Mathf.Repeat( value, 24.0f );  } }
public float Minutes { get { return m_minutes; } set { m_minutes = Mathf.Repeat( value, 60.0f ); } }
public float Seconds { get { return m_seconds; } set { m_seconds = Mathf.Repeat( value, 60.0f ); } }

private const float m_hourInSeconds = 3600.0f,
m_minuteInSeconds = 60.0f;

public void AddHours( float durationInHours ) { AddSeconds( durationInHours * m_hourInSeconds ); }
public void RandomizeTime()
{

}*/
}

void Start()
{
if(!activeTime)
{
//m_customTime.RandomizeTime();
rSeconds = UnityEngine.Random.Range(0, 60);
rMinutes = UnityEngine.Random.Range(0, 60);
rHours = UnityEngine.Random.Range(0, 12);
//m_customTime.SetTime(UnityEngine.Random.Range(0, 60), UnityEngine.Random.Range(0, 60), UnityEngine.Random.Range(0, 12));
m_customTime.SetTime(rSeconds, rMinutes, rHours);

}
}

void RandomizeTime()
{
rSeconds = UnityEngine.Random.Range(0, 60);
rMinutes = UnityEngine.Random.Range(0, 60);
rHours = UnityEngine.Random.Range(0, 12);
//m_customTime.SetTime(UnityEngine.Random.Range(0, 60), UnityEngine.Random.Range(0, 60), UnityEngine.Random.Range(0, 12));
m_customTime.SetTime(rSeconds, rMinutes, rHours);
}

void DisplayTime(float _seconds, float _minutes, float _hours)
{
if (m_customTime.militaryTime) { Debug.Log(ToMilitaryString(_seconds, _minutes, _hours)); }
else { Debug.Log("Display Time: " + ToStandardTime(_seconds, _minutes, _hours)); }
}

void DisplayTime()
{
if (m_customTime.militaryTime) { Debug.Log(ToMilitaryString(rSeconds, rMinutes, rHours)); }
else { Debug.Log("Display Time: " + ToStandardTime(rSeconds, rMinutes, rHours)); }
}

void Update()
{
if (Input.GetKey(KeyCode.R))
{
//m_customTime.SetTime(UnityEngine.Random.Range(0, 60), UnityEngine.Random.Range(0, 60), UnityEngine.Random.Range(0, 24));
rSeconds = UnityEngine.Random.Range(0, 60);
rMinutes = UnityEngine.Random.Range(0, 60);
rHours = UnityEngine.Random.Range(0, 12);
//m_customTime.SetTime(UnityEngine.Random.Range(0, 60), UnityEngine.Random.Range(0, 60), UnityEngine.Random.Range(0, 12));
m_customTime.SetTime(rSeconds, rMinutes, rHours);

}
if (useCustomTime)
{
if (activeTime)

int h = Mathf.FloorToInt(m_customTime.Hours);
int m = Mathf.FloorToInt(m_customTime.Minutes);
int s = Mathf.FloorToInt(m_customTime.Seconds);
Debug.Log("Line163");
Debug.Log("Time is " + h.ToString("00") + ":" + m.ToString("00") + ":" + s.ToString("00"));

//Debug.LogFormat("{0};{1};{2}", m_customTime.Hours.ToString("00"), m_customTime.Minutes.ToString("00"), m_customTime.Seconds.ToString("00"));
//Debug.Log("Line 165: Time = (" + m_customTime.Hours + "h * 60 " + "+ " + m_customTime.Minutes + "m)" + " * 60 + " + m_customTime.Seconds + "s = " + m_customTime.m_time);

if (analog)
{
hours.localRotation =
Quaternion.Euler(0f, 0f, m_customTime.Hours * -hoursToDegrees);
minutes.localRotation =
Quaternion.Euler(0f, 0f, m_customTime.Minutes * -minutesToDegrees);
seconds.localRotation =
Quaternion.Euler(0f, 0f, m_customTime.Seconds * -secondsToDegrees);

//hours.localRotation =
//    Quaternion.Euler(0f, 0f, m_customTime.Hours * -hoursToDegrees);
//minutes.localRotation =
//    Quaternion.Euler(0f, 0f, m_customTime.Minutes * -minutesToDegrees);
//seconds.localRotation =
//    Quaternion.Euler(0f, 0f, m_customTime.Seconds * -secondsToDegrees);

}
else
{
hours.localRotation =
Quaternion.Euler(0f, 0f, Mathf.RoundToInt(m_customTime.Hours) * -hoursToDegrees);
minutes.localRotation =
Quaternion.Euler(0f, 0f, Mathf.RoundToInt(m_customTime.Minutes) * -minutesToDegrees);
seconds.localRotation =
Quaternion.Euler(0f, 0f, Mathf.RoundToInt(m_customTime.Seconds) * -secondsToDegrees);
}

if (m_customTime.militaryTime) { Debug.Log(ToMilitaryString()); }
else { Debug.Log(ToStandardTime()); }
}
else
{
if (analog)
{
TimeSpan timespan = DateTime.Now.TimeOfDay;
hours.localRotation =
Quaternion.Euler(0f, 0f, (float)timespan.TotalHours * -hoursToDegrees);
minutes.localRotation =
Quaternion.Euler(0f, 0f, (float)timespan.TotalMinutes * -minutesToDegrees);
seconds.localRotation =
Quaternion.Euler(0f, 0f, (float)timespan.TotalSeconds * -secondsToDegrees);
}
else
{
DateTime time = DateTime.Now;
hours.localRotation = Quaternion.Euler(0f, 0f, time.Hour * -hoursToDegrees);
minutes.localRotation = Quaternion.Euler(0f, 0f, time.Minute * -minutesToDegrees);
seconds.localRotation = Quaternion.Euler(0f, 0f, time.Second * -secondsToDegrees);
}

DateTime currentTime = DateTime.Now;
DisplayTime();
//Debug.LogFormat("{0};{1};{2}", currentTime.Hour.ToString("00"), currentTime.Minute.ToString("00"), currentTime.Second.ToString("00"));

}
}

public string ToMilitaryString() // Otherwise known as digital representation I suppose.
{
//return string.Format("{0};{1};{2}", Hours.ToString("00"), Minutes.ToString("00"), Seconds.ToString("00"));
return string.Format("{0};{1};{2}", m_customTime.Hours.ToString("00"), m_customTime.Minutes.ToString("00"), m_customTime.Seconds.ToString("00"));
}

public string ToMilitaryString(float _seconds, float _minutes, float _hours) // Otherwise known as digital representation I suppose.
{
//return string.Format("{0};{1};{2}", Hours.ToString("00"), Minutes.ToString("00"), Seconds.ToString("00"));
return string.Format("{0};{1};{2}", m_customTime.Hours.ToString("00"), m_customTime.Minutes.ToString("00"), m_customTime.Seconds.ToString("00"));
}

public string ToStandardTime()
{
float clampedHours = m_customTime.Hours % 12; // Get rest time of 0 to 12, AM or PM.
string partOfDay = m_customTime.Hours > 12 ? "PM" : "AM";

// Should result in "10:34 AM" or "07:48 PM".
// Optionally you can get rid of using clamped hours if you just want to have the AM / PM postfix.
return string.Format("{0};{1};{2}", clampedHours.ToString("00"), m_customTime.Minutes.ToString("00"), m_customTime.Seconds.ToString("00")) + " " + partOfDay;
}

public string ToStandardTime(float _seconds, float _minutes, float _hours)
{
float clampedHours = m_customTime.Hours % 12; // Get rest time of 0 to 12, AM or PM.
string partOfDay = m_customTime.Hours > 12 ? "PM" : "AM";

// Should result in "10:34 AM" or "07:48 PM".
// Optionally you can get rid of using clamped hours if you just want to have the AM / PM postfix.
return string.Format("{0};{1};{2}", clampedHours.ToString("00"), m_customTime.Minutes.ToString("00"), m_customTime.Seconds.ToString("00")) + " " + partOfDay;
}
}
``````

Hey @Czar-Man, I upgraded the package for you!
This was actually quite a bit tougher than I thought!

Updated Package:

Changelist:

• Now able to set custom time.

• Now able to set seconds, minutes and hours individually.

• Now able to increment custom time with X seconds, minutes and hours.

• Now able to set time amplifier that speeds up custom time! (also works with negative values)

• Now debugs current time, remove it if you wish.

• Now takes looping into consideration when incrementing / setting time.

Original tutorial as from OP. (for other users)

``````using UnityEngine;
using System;

public class ClockAnimator : MonoBehaviour
{
private const float
hoursToDegrees = 360f / 12f,
minutesToDegrees = 360f / 60f,
secondsToDegrees = 360f / 60f;

public Transform hours, minutes, seconds;
public bool analog = true; // Smooth == true, Rigid TickTock == false.

public bool useCustomTime = true;
public float m_timeAmplifier = 20f;
public DayCycle m_customTime = new DayCycle();

[Serializable]
public class DayCycle
{
[SerializeField]
private float m_hours = 7, m_minutes = 5, m_seconds = 23;

public float Hours { get { return m_hours; } set { m_hours = Mathf.Repeat( value, 24.0f );  } }
public float Minutes { get { return m_minutes; } set { m_minutes = Mathf.Repeat( value, 60.0f ); } }
public float Seconds { get { return m_seconds; } set { m_seconds = Mathf.Repeat( value, 60.0f ); } }

private const float m_hourInSeconds = 3600.0f,
m_minuteInSeconds = 60.0f;

{
Hours += durationInSeconds / m_hourInSeconds;
Minutes += durationInSeconds / m_minuteInSeconds;
Seconds += durationInSeconds;
}

public void AddHours( float durationInHours ) { AddSeconds( durationInHours * m_hourInSeconds ); }
}

void Update()
{
if( useCustomTime )
{
Debug.LogFormat( "{0};{1};{2}", m_customTime.Hours.ToString( "00" ), m_customTime.Minutes.ToString( "00" ), m_customTime.Seconds.ToString( "00" ) );

if( analog )
{
hours.localRotation =
Quaternion.Euler( 0f, 0f, m_customTime.Hours * -hoursToDegrees );
minutes.localRotation =
Quaternion.Euler( 0f, 0f, m_customTime.Minutes * -minutesToDegrees );
seconds.localRotation =
Quaternion.Euler( 0f, 0f, m_customTime.Seconds * -secondsToDegrees );
}
else
{
hours.localRotation =
Quaternion.Euler( 0f, 0f, Mathf.RoundToInt( m_customTime.Hours ) * -hoursToDegrees );
minutes.localRotation =
Quaternion.Euler( 0f, 0f, Mathf.RoundToInt( m_customTime.Minutes ) * -minutesToDegrees );
seconds.localRotation =
Quaternion.Euler( 0f, 0f, Mathf.RoundToInt( m_customTime.Seconds ) * -secondsToDegrees );
}
}
else
{
if( analog )
{
TimeSpan timespan = DateTime.Now.TimeOfDay;
hours.localRotation =
Quaternion.Euler( 0f, 0f, ( float )timespan.TotalHours * -hoursToDegrees );
minutes.localRotation =
Quaternion.Euler( 0f, 0f, ( float )timespan.TotalMinutes * -minutesToDegrees );
seconds.localRotation =
Quaternion.Euler( 0f, 0f, ( float )timespan.TotalSeconds * -secondsToDegrees );
}
else
{
DateTime time = DateTime.Now;
hours.localRotation = Quaternion.Euler( 0f, 0f, time.Hour * -hoursToDegrees );
minutes.localRotation = Quaternion.Euler( 0f, 0f, time.Minute * -minutesToDegrees );
seconds.localRotation = Quaternion.Euler( 0f, 0f, time.Second * -secondsToDegrees );
}

DateTime currentTime = DateTime.Now;
Debug.LogFormat( "{0};{1};{2}", currentTime.Hour.ToString( "00" ), currentTime.Minute.ToString( "00" ), currentTime.Second.ToString( "00" ) );
}
}
}
``````

To set the time, just use:

``````        // For Time Setting.
m_customTime.Minutes = 30f;