This is because of the way how GUI applications work. A GUI application can be understood as an infinite loop with a message queue. When a button is clicked, os something like that, an event is fired. Events are then executed in order.
Changeing the GUI is also done via events. When you set the caption of the label, this sends a change caption event to that label. But the change will only be executed when all prior events finished.
You are sending that event from your FormCreate event. So, the changes can only take place if that FormCreate event finished. It finishes when your procedure is exited, i.e. after the last line of code in that function. This means, you send an event to change the label, then wait and send another event, but the previous event couldn't be executed. So once your function returns, both events get executed directly after another, meaning the change will be instant.
To solve this you can manually call the message queue and tell it to handle all waiting messages before continuing:
Label1.Caption:=TimeToStr(now);
Application.ProcessMessages; // handle the message created by updating the caption
sleep(1000);
Label1.Caption:=TimeToStr(now);
But this also executes user messages like clicks on buttons, so be careful with that call.
You don't have the problem with the timer, because your each tick of your timer is exactly one event, so once the timer ticks, you change the label, the function returns and the lable changed event can be executed directly afterwards