Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Simulation Style Date/Time

Discussion in 'Scripting' started by xrolliox, Feb 11, 2017.

  1. xrolliox

    xrolliox

    Joined:
    May 5, 2016
    Posts:
    55
    Hey,

    I'm trying to get a simulation style date & time to run in my game, and I want it to display in a dd/mm/yy fashion.

    I want it to be a "fake" time not the system time. My current script is just outputting 0.000000 or a 00/00/45 (yy/mm/dd - even though I have specified that there are 365(days) / 12(months) in the script.)

    I just need this to show the player how much time has passed in-game, and so I can set the income function at the end of the each day. Anybody got any ideas on how to code a date system like that?
     
  2. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Try posting your code you have now, and we can see where you've gone wrong. Remember to use code tags (the icon to the left of the Save Icon near the end). Either you don't have enough time to show months or years (though the fact you have 45 days seems to suggest some other bug), or maybe your using ints instead of floats and getting rounding errors? Could be a lot of things.
     
  3. xrolliox

    xrolliox

    Joined:
    May 5, 2016
    Posts:
    55
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class Clock : MonoBehaviour
    7. {
    8.     public double totalGameSeconds;
    9.     public Text time;
    10.  
    11.     public double seconds;
    12.     public double minutes;
    13.     public double hours;
    14.     public double days;
    15.     public double months;
    16.     public double years;
    17.  
    18.     private double secondsPerSecond;
    19.  
    20.  
    21.  
    22.     void Start()
    23.     {
    24.  
    25.         secondsPerSecond = 3600;
    26.         totalGameSeconds += secondsPerSecond * Time.deltaTime;
    27.  
    28.  
    29.     }
    30.  
    31.  
    32.     void Update()
    33.     {
    34.  
    35.         if (Input.GetKeyDown(KeyCode.Alpha1))
    36.         {
    37.             secondsPerSecond = 3600;
    38.  
    39.  
    40.         }
    41.         else if (Input.GetKeyDown(KeyCode.Alpha2))
    42.         {
    43.             secondsPerSecond = 86400;
    44.         }
    45.         totalGameSeconds += secondsPerSecond * Time.deltaTime;
    46.  
    47.         seconds = totalGameSeconds;
    48.         minutes = totalGameSeconds / 60;
    49.         hours = minutes / 60;
    50.         days = hours / 24;
    51.         months = days / (365 / 12);
    52.         years = months / 12;
    53.  
    54.         time.text = (days + months + years).ToString();
    55.        
    56.  
    57.     }
    58.  
    59.  
    60. }
    I did change the function in ToString to "##/##/##" but that counted to 45 'days' and without that it just counts 0.00000^
     
  4. Cyras

    Cyras

    Joined:
    Nov 26, 2012
    Posts:
    14
    I can't spend enough time right now to check everything. But there are 2 things:

    1st:
    Code (csharp):
    1. (days + months + years).ToString()
    will first calculate (days + months + years) and then transform it into a string. Not sure if that's really what you want.

    2nd: I'm pretty sure you want 60 seconds per minute, 60 minutes per hour and so on. So why are you calculating
    Code (csharp):
    1.  minutes = totalGameSeconds / 60
    for example? That will result in having more than 60 minutes at some point. Don't you want
    Code (csharp):
    1.  minutes = totalGameSeconds % 60
    ? (Modulo, gives a range from 0 to x)
     
  5. xrolliox

    xrolliox

    Joined:
    May 5, 2016
    Posts:
    55
    Altering the / = % seemed to have a positive effect on the code, but I still can't get it ti display the date as dd/mm/yy.
     
  6. Cyras

    Cyras

    Joined:
    Nov 26, 2012
    Posts:
    14
    There are multiple ways I can think of that will do what you want. Give me a second and I may give you 1-2.
     
  7. xrolliox

    xrolliox

    Joined:
    May 5, 2016
    Posts:
    55
    That would be great - thank you. :)
     
  8. Cyras

    Cyras

    Joined:
    Nov 26, 2012
    Posts:
    14
    This code is neither perfect nor does it represent a final solution, but it works.

    Code (csharp):
    1.  
    2.     static void Update()
    3.     {
    4.       totalGameSeconds += secondsPerSecond *Time.deltaTime;
    5.  
    6.       int currentSeconds = (int)totalGameSeconds;
    7.  
    8.       seconds = currentSeconds;
    9.       minutes = currentSeconds % 60;
    10.       hours = currentSeconds / 60 % 60;
    11.       days = currentSeconds / (60*60) % 24;
    12.       months = currentSeconds / (60*60*24) % 30;
    13.       years = currentSeconds / (60*60*24*30) % 12;
    14.  
    15.       time.text = String.Format("{0}/{1}/{2}", days, months, years);
    16.     }
    17.  
    There are no changes needed except those. You may want to change seconds, minutes etc. to int though. This code also only handles months that have 30 days - changing the (30) every time the month increases by one will change that.

    Please for future coding capitalize the names of public fields and properties.^

    Edit: Changed a small testing value.
     
  9. xrolliox

    xrolliox

    Joined:
    May 5, 2016
    Posts:
    55
    This seems to be working great! Now I just need a way of setting the year start date - will that be as simple as setting an int number for it?
     
  10. Cyras

    Cyras

    Joined:
    Nov 26, 2012
    Posts:
    14
    Yea, setting totalGameSeconds in the start method to the value you need, will give the initial date.
     
  11. xrolliox

    xrolliox

    Joined:
    May 5, 2016
    Posts:
    55
    Okay, I changed the totalGameSeconds to (63608112000) for 2017 and have changed the values over to float as opposed to doubles, now this line is throwing an error about converting doubles to floats.

    Code (CSharp):
    1. totalGameSeconds += secondsPerSecond * 0.50;
     
  12. Cyras

    Cyras

    Joined:
    Nov 26, 2012
    Posts:
    14
    Code (csharp):
    1.  
    2. public double totalGameSeconds;
    3. public Text time;
    4. public int seconds;
    5. public int minutes;
    6. public int hours;
    7. public int days;
    8. public int months;
    9. public int years;
    10. private double secondsPerSecond;
    11.  
    This should work for you.

    For future reference: If you get an exception, that you can not convert comething implicitly, cast it explicitly

    Example:

    Code (csharp):
    1.  
    2. public int value1;
    3. public double value2;
    4.  
    5. static void Update(){
    6.     value1 = (int) value2;
    7. }
    8.  
     
  13. xrolliox

    xrolliox

    Joined:
    May 5, 2016
    Posts:
    55
    I've tried it, threw up an error with CurrentSeconds so I tried casting that to a float (and subsequently all of the seconds/minutes = currentSeconds etc to floats) but that didn't work.

    My clock now says -3/-15/00 or it's at 23.something with either int's or floats. Either way it doesn't budge.
     
  14. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    its because the max value of an int is 2^31 or about about 2 billion. anything bigger than that overflows into negatives. Best to just use floats and convert to ints as we need. Also we should work from years on down.
    Think of the date like a regular number 346.
    • First divide by 100 to get 3 (years). Then subtract 3*100 from the number
    • Now we have 46.. divide by 10 to get 4 (months) then subtract 4*10 from the number
    • now we have 6 leftover our days.
    Here is a TimeKeeper class.
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using System.Text;
    6.  
    7. public class TimeKeeper : MonoBehaviour {
    8.  
    9.     // Set this in the inspector
    10.     public int StartYear;
    11.     public int StartMonth;
    12.     public int StartDay;
    13.     public int StartHour;
    14.     public int StartMinute;
    15.     public int StartSecond;
    16.  
    17.  
    18.     private float gameTime;
    19.     private const float MinToSec = 60;
    20.     private const float HourToSec = 60 * 60;
    21.     private const float DayToSec = 60 * 60 * 24;
    22.     private const float MonthToSec = 60 * 60 * 24 * 30;
    23.     private const float YearToSec = 60 * 60 * 24 * 30 * 12;
    24.  
    25.     void Start () {
    26.      
    27.         gameTime += StartSecond;
    28.         gameTime += StartMinute * MinToSec;
    29.         gameTime += StartHour * HourToSec;
    30.         gameTime += StartDay * DayToSec;
    31.         gameTime += StartMonth * MonthToSec;
    32.         gameTime += StartYear * YearToSec;
    33.      
    34.     }
    35.  
    36.     public void AddYear(int years)
    37.     {
    38.         AddTime((float)years * YearToSec);
    39.     }
    40.  
    41.     public void AddMonth(int months)
    42.     {
    43.         AddTime((float)months * MonthToSec);
    44.     }
    45.  
    46.     public void AddDay(int Days)
    47.     {
    48.         AddTime((float)Days * DayToSec);
    49.     }
    50.     public void AddTime(float sec)
    51.     {
    52.         gameTime += sec;
    53.     }
    54.     public string GetTime()
    55.     {
    56.         StringBuilder sb = new StringBuilder();
    57.         float currentTime = gameTime;
    58.  
    59.         int currentYear = (int)(gameTime / YearToSec);
    60.         currentTime -= currentYear;
    61.  
    62.         int currentMonth = (int)(gameTime / MonthToSec);
    63.         currentTime -= currentMonth;
    64.  
    65.         int currentDay = (int)(gameTime / DayToSec);
    66.         currentTime -= currentMonth;
    67.  
    68.         int currentHour = (int)(gameTime / HourToSec);
    69.         currentTime -= currentHour;
    70.  
    71.         int currentMinute = (int)(gameTime / MinToSec);
    72.         currentTime -= currentMinute;
    73.  
    74.         int currentSecond = (int)gameTime;
    75.  
    76.         sb.Append(currentYear);
    77.         sb.Append("//");
    78.         sb.Append(currentMonth);
    79.         sb.Append("//");
    80.         sb.Append(currentDay);
    81.  
    82.         return sb.ToString();
    83.     }
    84.  
    85. }
    86.  

    I added the core functionality to have Years/Days/Months/Hours/Minutes/Seconds. But the code only return Year/Months/Days .. you can extend it to hours/min/seconds easily enough. I assumed your keeping track of your own time so I didn't have an Update function add the passing seconds. Your game should just add Days/Months/Years to the time through the functions provided. If you want to add Hours/Minutes/Seconds just add the functions in as well should be easy to see how its working. Also you can set the initial date in the inspector and it calculates the correct number for you.

    At the top I added the constants for converting from Years/months/days.... into seconds You can change these around if you decide to have a custom calendar.
     
  15. xrolliox

    xrolliox

    Joined:
    May 5, 2016
    Posts:
    55
    I've added an update field to display the date on a Text object, but when I add "2017" as a year it displays 726261/24.
    Code (CSharp):
    1. void Update()
    2.     {
    3.         date.text = GetTime();
    4.     }
    It also doesn't count upwards on play.
     
  16. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Maybe change Get time to this:
    Code (CSharp):
    1. public string[] GetTime()
    2.     {
    3.        
    4.         float currentTime = gameTime;
    5.         int currentYear = (int)(gameTime / YearToSec);
    6.         currentTime -= currentYear;
    7.         int currentMonth = (int)(gameTime / MonthToSec);
    8.         currentTime -= currentMonth;
    9.         int currentDay = (int)(gameTime / DayToSec);
    10.         currentTime -= currentMonth;
    11.         int currentHour = (int)(gameTime / HourToSec);
    12.         currentTime -= currentHour;
    13.         int currentMinute = (int)(gameTime / MinToSec);
    14.         currentTime -= currentMinute;
    15.         int currentSecond = (int)gameTime;
    16.         string[] times = new string[3];
    17.         times[0] = currentYear.ToString();
    18.         times[1] = currentMonth.ToString();
    19.         times[2] = currentDay.ToString();
    20.         return times;
    21.     }
    22.  
    Then other code would do this:
    Code (CSharp):
    1. string[] times = GetTime();
    2. date.text = times0];
    3. // or
    4. date.text  = times[0] + " : " + times[1] + " : " + times[2];
     
  17. zevonbiebelbrott

    zevonbiebelbrott

    Joined:
    Feb 14, 2021
    Posts:
    118
    Here you go. 5 years later, this answer actually works, took me 5 minutes btw:


    Code (CSharp):
    1. public string GetTime()
    2.     {
    3.         float currentTime = gameTime;
    4.         int currentYear = (int)(currentTime / YearToSec);
    5.         currentTime -= currentYear * YearToSec;
    6.         int currentMonth = (int)(currentTime / MonthToSec);
    7.         currentTime -= currentMonth * MonthToSec;
    8.         int currentDay = (int)(currentTime / DayToSec);
    9.         currentTime -= currentDay * DayToSec;
    10.         int currentHour = (int)(currentTime / HourToSec);
    11.         currentTime -= currentHour * HourToSec;
    12.         int currentMinute = (int)(currentTime / MinToSec);
    13.         currentTime -= currentMinute * MinToSec;
    14.  
    15.         int currentSecond = (int)currentTime;
    16.  
    17.         string times =
    18.            currentDay.ToString() + "/"
    19.          + currentMonth.ToString() + "/"
    20.          + currentYear.ToString();
    21.  
    22.         return times;
    23.         }
     
    Last edited: Nov 13, 2022
  18. Nad_B

    Nad_B

    Joined:
    Aug 1, 2021
    Posts:
    655
    All these complicated code to calculate dates/time from above can be replaced with just three lines using .NET
    TimeSpan
    class.

    Code (CSharp):
    1. // Code not tested...
    2. public class GameTimeManager : MonoBehavior
    3. {
    4.     private float _elapsedTime;
    5.  
    6.     private readonly DateTime _startDate = new DateTime(1945, 1, 1);
    7.  
    8.     [SerializeField]
    9.     private float _secondsPerDay = 1f; // How much in-game days will pass in 1 real-time second
    10.  
    11.     public DateTime CurrentDate { get; private set; }
    12.  
    13.     public static GameTimeManager Instance { get; private set; }
    14.  
    15.     private void Update()
    16.     {
    17.         _elapsedTime += Time.deltaTime;
    18.  
    19.         var elapsedDays = _elapsedTime / _secondsPerDay;
    20.         var elapsedTimeSpan = TimeSpan.FromDays(elapsedDays);
    21.  
    22.         CurrentDate = _startDate.Add(elapsedTimeSpan);
    23.     }
    24.  
    25.     // Singleton stuff here...
    26.     private void Awake()
    27.     {
    28.         Instance = this;
    29.     }
    30. }
    31.  
    32. // Usage to get the game's simulated Date:
    33.  
    34. Debug.Log(GameTimeManager.Instance.CurrentDate);
    35. Debug.Log(GameTimeManager.Instance.CurrentDate.ToString("dd/MM/yyyy"));
    36. // For Date string format check: https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings
     
    Last edited: Nov 14, 2022
  19. zevonbiebelbrott

    zevonbiebelbrott

    Joined:
    Feb 14, 2021
    Posts:
    118
    Its no fun like that, its a lot more fun to re invent the wheel just because you need to display a date and time somewhere once in your whole game
     
    Nad_B likes this.