Why doesn't this energy refill code work when I'm not on the game?

Hi guys! So I have written an energy refill script:

if(Reference.energy < 20 && PlayerPrefs.GetInt("Key_2") == 0)
        {
            PlayerPrefs.SetString("Key_1", DateTime.Now.ToString());
            PlayerPrefs.SetInt("Key_2", 1);
            Debug.Log("Refill");
        }
        if(PlayerPrefs.GetInt("Key_2") == 1)
        {
            refillTime = DateTime.Now.Subtract(DateTime.Parse(PlayerPrefs.GetString("Key_1")));
            if(refillTime.TotalSeconds > 5)
   //Refill time of 5 seconds for testing purposes
            {
                Reference.energy += (int)refillTime.TotalSeconds / 5;
                counter.text = "Energy: " + Reference.energy + "/20";
                PlayerPrefs.SetInt("Key_0", Reference.energy);
                PlayerPrefs.SetInt("Key_2", 0);
            }

It works beautifully when I’m playing the game, every five seconds the energy counter goes up by 1. However, if I exit my game for 20 seconds, and the energy should increase by 4, it still stays on the same amount as it was when I exited my game. WHy is this happening and how can I fix it? Thanks!

I just did some testing and this seems to work perfectly, it should also be more efficient than your version.

using System;
using UnityEngine;

public class EnergyTest : MonoBehaviour {
    int energy;

    int nextTimeToGiveEnergy = 5;

    void Start()
    {
        energy = PlayerPrefs.GetInt("energy"); //get energy from Prefs

        int timeOffline = (int)DateTime.Now.Subtract(DateTime.Parse(PlayerPrefs.GetString("lastTimeEnergyGiven"))).TotalSeconds; //calculate time offline as an int
        while (timeOffline > 5 && energy < 20) //doing this so we can limit energy to 20
        {
            energy += 1;
            timeOffline -= 5;
        }

        PlayerPrefs.SetInt("energy", energy); //save energy again 
        PlayerPrefs.SetString("lastTimeEnergyGiven", DateTime.Now.ToString()); //save the time, because the user just got energy

        Debug.Log(energy); //testing purposes
    }
	
	void Update () {
		if (Time.time >= nextTimeToGiveEnergy) //Time.time is incremented every second, with 0 being the second the game began.
        { //Code is ran every 5 seconds, it also is more efficient than DateTime.now
            nextTimeToGiveEnergy += 5; //It will run again in 5 seconds
            energy++; //increment energy by one
            PlayerPrefs.GetInt("energy", energy); //save energy
            PlayerPrefs.SetString("lastTimeEnergyGiven", DateTime.Now.ToString()); //save the last time energy was given, cannot be Time.time
            Debug.Log(energy); //testing purposes
        }
    }
}

There are some obvious problems that would show when the energy is refilled less frequently, let’s say 5 minutes. For example, if you were offline for 3 minutes, when logging in the timer would reset. This is fairly easy to fix, but I’ll leave the code up to you.

I am also not sure if having the loop this way is faster than having a coroutine with an infinite loop and a yield new WaitForSeconds(5)

Just realised, another problem is the fact that the first time you run it, it will throw an error, because PlayerPrefs.GetString(“lastTimeEnergyGiven”) will return null, and Date time won’t be able to cast it

maybe you are running into an issue when casting it as an int. try changing line 13 to this,

 Reference.energy += Mathf.FloorToInt(refillTime.TotalSeconds / 5);