Converting float (0.0 - 1.0) to hours/minutes?

Hi all.

I’m trying to create a Time of Day script, using Unity 5. Is there a way to calculate the actual time of day with the values that fCurrentTimeOfDay gives (a float between 0.0 - 1.0) - 0.0 being 00:00 and 1.0 being 23:59…

Here’s the script:

using UnityEngine;
using System.Collections;

public class TOD_Base : MonoBehaviour {

    public Light lSun;
    public float fSecondsDefaultDay;

    [Range(0, 1)]
    public float fCurrentTimeOfDay = 0.0f;

    [HideInInspector]
    public float fTimeMultiplier = 1.0f;
    private float fSunStartIntensity;

    public int currentDay = 1;
    public int currentMonth = 5;
    public int currentYear = 2015;

    void Start()
    {
        fSunStartIntensity = lSun.intensity;
    }

    void Update()
    {
        UpdateSun();

        // Control the speed of our "clock"
        fCurrentTimeOfDay += (Time.deltaTime / fSecondsDefaultDay) * fTimeMultiplier;

        // Resets our time of day to 0
        if (fCurrentTimeOfDay >= 1)
        {
            fCurrentTimeOfDay = 0;

            currentDay += 1;
            if(currentDay == 32)
            {
                currentDay = 1;
                currentMonth += 1;
                if(currentMonth == 13)
                {
                    currentMonth = 1;
                    currentYear += 1;
                    currentDay = 1;
                }
            }

            Debug.Log("Current date: " + currentDay + "/" + currentMonth + "/" + currentYear);
        }
    }

    void UpdateSun()
    {
        // Rotate the sun 360 degress in X-axis according to our current time of day
        lSun.transform.localRotation = Quaternion.Euler((fCurrentTimeOfDay * 360) - 90f, 170, 0);
       
        // Set the sun to full intesity during the day
        float fIntensityMultiplier = 1.0f;

        if (fCurrentTimeOfDay <= 0.23f || fCurrentTimeOfDay >= 0.75f)
        {
            fIntensityMultiplier = 0.0f;
        }
        else if (fCurrentTimeOfDay <= 0.25f)
        {
            fIntensityMultiplier = Mathf.Clamp01((fCurrentTimeOfDay - 0.23f) * (1 / 0.02f));
        }
        else if (fCurrentTimeOfDay >= 0.75f)
        {
            fIntensityMultiplier = Mathf.Clamp01(1 - ((fCurrentTimeOfDay - 0.73f) * (1 / 0.02f)));
        }

        // Multuply the intensity of the sun according to the time of day
        lSun.intensity = fSunStartIntensity * fIntensityMultiplier;
    }
}

if you’re only going to “minute” accuracy, there are 1440 minutes in a 24 hour period, your normalised value times by that will give you the current time in “minutes”, then you just need to format that into hours/minutes.

Debug.Log((int)(x / 60) + ":" + (int)(x % 60));

x being the result of the calculation suggested

2 Likes

Thank you very much, mister! :slight_smile:

float sec;
        sec = fCurrentTimeOfDay * 86400;

        TimeSpan timeSpan = TimeSpan.FromSeconds(sec);
        string timeText = string.Format("{0:smile:2}:{1:smile:2}", timeSpan.Hours, timeSpan.Minutes);

I ended up using this solution instead. But…

In the inspector I set the time to start the scene at setting the normalised value, I’ve created two public ints (tHour and tMinute) - maybe a Vector2-solution is better(?). Is there a way to convert tHour and tMinute to a normalized value? It’s kind of a pain in the a… to try to set the correct time using the normalised value…

1 Like

Just work backwards. Properties can be a huge help here too.

Note, System.TimeSpan has multiple ‘from’ methods. FromSeconds, FromMinutes, FromDays, and more.

As well as a ToString that accepts really simple inputs for formatting:

var timeSpan = System.TimeSpan.FromDays(fCurrentTimeOfDay);
string timeText = timeSpan.ToString(@"hh\:mm");
1 Like

I’ve been scratching my head over this for a while now…

public string stringTime = "00:45";

    void Start()
    {
        TimeSpan timeSpan = TimeSpan.FromDays(fCurrentTimeOfDay);
        stringTime = timeSpan.ToString();
        Debug.Log("TIME: " + stringTime);
    }

I have NO IDEA how to convert stringTime to normalised float. Been googling until my fingers hurt how to convert strings to normalised floats but not with the result I was hoping for… I don’t know how much of a difference it makes that the designer can type either “00:45” or “00:45:31” into stringTime in the inspector, but not only hours… :slight_smile:

I want fCurrentTimeOfDay to equal the normalised float value of the string stringTime…

I hope I understood correctly:

            float fCurrentTimeOfDay = 0.654f;
            string stringTime = "00:45";
            TimeSpan timeSpan = TimeSpan.FromDays(fCurrentTimeOfDay);
            stringTime = timeSpan.ToString();
            Console.WriteLine("fCurrentTimeOfDay: " + fCurrentTimeOfDay);
            Console.WriteLine("TIME: " + stringTime);
            // 0 == 0, 1 == 24, 0.5 == 12
            Console.WriteLine("Map: " + Map(fCurrentTimeOfDay, 0, 1, 0, 24));

            var split = stringTime.Split(':');
            int hours = Int32.Parse(split[0]);
            int minutes = Int32.Parse(split[1]);
            float roundedSeconds = float.Parse(split[2].Replace('.', ','));
            int seconds = (int)Math.Round(roundedSeconds);
            Console.WriteLine("hours: " + hours);
            Console.WriteLine("minutes: " + minutes);
            Console.WriteLine("seconds: " + seconds);
            Console.WriteLine("Total minutes: " + (hours * 60 + minutes + seconds / 60));
            // 0 == 0, 1440 == 1, 720 == 0.5
            Console.WriteLine("Map: " + Map(hours * 60 + minutes + seconds / 60.0f, 0, 1440, 0, 1));
        /// <summary>
        /// maps value (which is in the range leftMin - leftMax) to a value in the range rightMin - rightMax
        /// </summary>
        /// <param name="value">Value.</param>
        /// <param name="leftMin">Left minimum.</param>
        /// <param name="leftMax">Left max.</param>
        /// <param name="rightMin">Right minimum.</param>
        /// <param name="rightMax">Right max.</param>
        public static float Map(float value, float leftMin, float leftMax, float rightMin, float rightMax)
        {
            return rightMin + (value - leftMin) * (rightMax - rightMin) / (leftMax - leftMin);
        }

Don’t know if I implemented it wrong or not, but I couldn’t get it to work…
It seems that only adjusting the fCurrentTimeOfDay changes the stringTime to the correct time, but not the other way around. If I type “14:30” or “14:30:00” into stringTime in the inspector, fCurrentTimeOfDay stays unchanged… and when the game starts the time starts at “00:00:00” no matter what I set it to in the inspector.

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;

[ExecuteInEditMode]
public class TOD_Base : MonoBehaviour {

    private Player_Base plBase;

    [Header("UI")]
    public Text timeTextUI;
    public Text dateTextUI;
    public Text seasonTextUI;

    [Header("Seasons")]
    [SerializeField] private string seasonSpring = "Spring";
    [SerializeField] private string seasonSummer = "Summer";
    [SerializeField] private string seasonAutumn = "Autumn";
    [SerializeField] private string seasonWinter = "Winter";

    [Header("Ambient Settings")]
    // This will change the ambient light depending on the time of day
    public Gradient ambientLight;
    public AnimationCurve ambientIntensity;   

    [Header("TOD Settings")]
    public Light lSun;

    public float fSecondsDefaultDay;

    [Space(5)]
    [Range(0, 1)] public float fCurrentTimeOfDay;
    public string stringTime = "14:30";

    [HideInInspector]
    public float fTimeMultiplier = 1.0f;
    public float fSunStartIntensity;

    public int currentDay = 1;
    public int currentMonth = 5;
    public int currentYear = 2015;

    private int hours;
    private int minutes;
    private int seconds;

    void Start()
    {
        plBase = (Player_Base)FindObjectOfType<Player_Base>();
        lSun.intensity = fSunStartIntensity;

        TimeSpan timeSpan = TimeSpan.FromDays(fCurrentTimeOfDay);
        stringTime = timeSpan.ToString();

        Debug.Log("fCurrentTimeOfDay: " + fCurrentTimeOfDay);
        Debug.Log("TIME: " + stringTime);
        Debug.Log("Map: " + Map(fCurrentTimeOfDay, 0, 1, 0, 24));

        var split = stringTime.Split(':');
        hours = Int32.Parse(split[0]);
        minutes = Int32.Parse(split[1]);
        float roundedSeconds = float.Parse(split[2].Replace('.', ','));
        seconds = (int)Math.Round(roundedSeconds);

        fCurrentTimeOfDay = Map(hours * 60 + minutes + seconds / 60f, 0, 1440, 0, 1);

        Debug.Log("Hours: " + hours);
        Debug.Log("Minutes: " + minutes);
        Debug.Log("Seconds: " + seconds);
        Debug.Log("Total minutes: " + (hours * 60 + minutes + seconds / 60f));
        Debug.Log("Map: " + Map(hours * 60 + minutes + seconds / 60.0f, 0, 1440, 0, 1));
    }

    void Update()
    {
        TimeSpan timeSpan = TimeSpan.FromDays(fCurrentTimeOfDay);

        fCurrentTimeOfDay += (Time.deltaTime / fSecondsDefaultDay) * fTimeMultiplier;
        stringTime = Map(hours * 60 + minutes + fSecondsDefaultDay / 60f, 0, 1440, 0, 1).ToString();
        stringTime = timeSpan.ToString();

        SetAmbientLight(fCurrentTimeOfDay);

        // Calculate actual time of day in HH:mm:ss for the HUD
        float sec;
        sec = fCurrentTimeOfDay * fSecondsDefaultDay;

        timeSpan = TimeSpan.FromSeconds(sec);
        string timeText = string.Format("{0:smile:2}:{1:smile:2}:{2:smile:2}", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds);

        timeTextUI.text = timeText;

        // Resets our time of day to 0
        if (fCurrentTimeOfDay >= 1)
        {
            fCurrentTimeOfDay = 0;

            currentDay += 1;

            if(currentDay == 32)
            {
                currentDay = 1;
                currentMonth += 1;

                if(currentMonth == 13)
                {
                    currentMonth = 1;
                    currentYear += 1;
                    currentDay = 1;
                }
            }
        }

        dateTextUI.text = currentDay + "/" + currentMonth + "/" + currentYear;

        // Set current season
        if(currentMonth >= 10 && currentMonth <= 12)
        {
            seasonTextUI.text = seasonWinter;
        } else if(currentMonth >= 8 && currentMonth <= 10)
        {
            seasonTextUI.text = seasonAutumn;
        } else if(currentMonth >= 5 && currentMonth <= 8)
        {
            seasonTextUI.text = seasonSummer;
        } else if(currentMonth >= 2 && currentMonth <= 5)
        {
            seasonTextUI.text = seasonSpring;
        } else
        {
            seasonTextUI.text = seasonWinter;
        }

        UpdateSun();
    }

    public static float Map(float value, float leftMin, float leftMax, float rightMin, float rightMax)
    {
        return rightMin + (value - leftMin) * (rightMax - rightMin) / (leftMax - leftMin);
    }

    void UpdateSun()
    {
        // Rotate the sun 360 degress in X-axis according to our current time of day
        lSun.transform.localRotation = Quaternion.Euler((fCurrentTimeOfDay * 360) - 90f, 130, 0);
       
        // Set the sun to full intesity during the day
        float fIntensityMultiplier = 1.0f;

        if (fCurrentTimeOfDay <= 0.23f || fCurrentTimeOfDay >= 0.75f)
        {
            fIntensityMultiplier = 0.0f;
        }
        else if (fCurrentTimeOfDay <= 0.25f)
        {
            fIntensityMultiplier = Mathf.Clamp01((fCurrentTimeOfDay - 0.23f) * (1 / 0.02f));
        }
        else if (fCurrentTimeOfDay >= 0.75f)
        {
            fIntensityMultiplier = Mathf.Clamp01(1 - ((fCurrentTimeOfDay - 0.73f) * (1 / 0.02f)));
        }

        // Multiply the intensity of the sun according to the time of day
        lSun.intensity = fSunStartIntensity * fIntensityMultiplier;
    }

    void SetAmbientLight(float _currentTime)
    {
        RenderSettings.ambientLight = ambientLight.Evaluate(_currentTime);
        RenderSettings.ambientIntensity = ambientIntensity.Evaluate(_currentTime);
        lSun.color = ambientLight.Evaluate(_currentTime);
    }
}

Maybe this help:
2323326--156719--2015-10-03_14-55-36.gif

public class NewBehaviourScript : MonoBehaviour
{
    public enum ParameterType
    {
        FLOAT,
        STRING
    }

    public ParameterType Type;
    [Range(0, 1)]
    public float fCurrentTimeOfDay;
    public string stringTime = "14:30";

    void Start()
    {
        switch (Type)
        {
            case ParameterType.FLOAT:
                // if you want use float to know stringTime use:
                stringTime = FloatToTime(fCurrentTimeOfDay);
                break;
            case ParameterType.STRING:
                // if you want use stringTime to know float use
                fCurrentTimeOfDay = TimeToFloat(stringTime);
                break;
        }
    }

    // to check in real time
    void Update()
    {
        switch (Type)
        {
            case ParameterType.FLOAT:
                // if you want use float to know stringTime use:
                stringTime = FloatToTime(fCurrentTimeOfDay);
                break;
            case ParameterType.STRING:
                // if you want use stringTime to know float use
                fCurrentTimeOfDay = TimeToFloat(stringTime);
                break;
        }
    }

    /// <summary>
    /// maps value (which is in the range leftMin - leftMax) to a value in the range rightMin - rightMax
    /// </summary>
    /// <param name="value">Value.</param>
    /// <param name="leftMin">Left minimum.</param>
    /// <param name="leftMax">Left max.</param>
    /// <param name="rightMin">Right minimum.</param>
    /// <param name="rightMax">Right max.</param>
    public static float Map(float value, float leftMin, float leftMax, float rightMin, float rightMax)
    {
        return rightMin + (value - leftMin) * (rightMax - rightMin) / (leftMax - leftMin);
    }

    public float TimeToFloat(string time)
    {
        // "11:12:13" became ["11","12","13"] or "11:12" became ["11","12"]
        var split = time.Split(':');
        float temp = 60;
        // total minutes
        float minutes = 0;
        // first stringPart value is hours, second - minutes, third - seconds
        int i = 0;
        foreach (var stringPart in split)
        {
            // "11.12" became 13.12f or "11" became 11.0f
           float value = float.Parse(stringPart, CultureInfo.InvariantCulture);
            // 13.12f became 13 or 13.66f became 14
            int roundedValue = (int)Math.Round(value);
            // if stringPart = hours, we should MULTIPLY this value by 60 to get minutes
            // if stringPart = minutes
            // if stringPart = seconds, we should DIVIDE this value by 60 to get minutes
            minutes += roundedValue * temp;
            // first time this value = 60(hours), then 1(minutes), and then 1/60(seconds)
            temp /= 60.0f;
        }
        // then we map current minutes value, if total minutes = 720, then our float value = 0.5f
        return Map(minutes, 0, 1440, 0, 1);
    }

    public string FloatToTime(float time)
    {
        TimeSpan timeSpan = TimeSpan.FromDays(fCurrentTimeOfDay);
        if (fCurrentTimeOfDay == 1)
            return "24:00:00";
        return string.Format("{0:g}", timeSpan);
    }
}
2 Likes

I will give that a try later today! Looks promising! :slight_smile:

Thank you! That solution worked just as expected! :slight_smile: