I don't know much about firing off things based off events or interrupts and whatnot, but i think you could have a simple loop checking the time every X often, then if that matches certain conditions fire off the required code. There is a time library that lets you get the hour() and minute(). Checking if the time is 10am would be seeing if hour() is 10, then if minute() is 0. Once both are true, fire the lights on code and return to the time checking loop when done. Or if you don't want to use ifs you can use a switch... If you check too fast, you will fire that code many times obviously, even checking it every 30 seconds would possibly fire it twice. You could check only every minute, or check however fast you want and put an extra variable for has the code run today, which is set to true the first time its run and set to false at midnight or when the code to turn whatever it was off is run.
Pseudocode...
bool lightsOn = false
while true{
switch (hour()){
case 0 ... case 9
break
case 10
if lightsOn == false{
run lightsOn()
lightsOn = true}
break
case 11 ... 21
break
case 22
if lightsOn == true{
run lightsOff()
lightsOn = false}
break
}
pause X
}
May not be efficient, and 'programming' the relay times involves changing the actual sketch... This also is only checking every hour interval, but you can add further checks in those hour slots you care about to check down to whatever increment you want. Aiming for a window too small (like an exact second) could result in it never happening if you check only every 10 seconds or so, so be aware of that.