The shell has an eerie set of syntax alternatives for conditionals.
The [ is not a traditional delimiter, but the name of a command. The way to use it for multiple expressions is like this:
if [ "$h" -gt 9 ] && [ "$h" -lt 21 ]; then
...
fi
A slightly newer (that is, post-1979 or so ...) syntax is
if [ "$h" -gt 9 -a "$h" -lt 21 ]; then
...
fi
The $((...)) syntax is much newer, and introduces proper arithmetic (including the > and < operators) but is not directly usable as a condition. It simply expands to 0 for false and 1 for true. But of course, you can mix and match:
if [ $((h > 9 && h < 21)) == 1 ]; then
...
fi
Finally, there is the [[ ... ]] conditional, which is probably what you are after:
if [[ $h > 9 ]] && [[ $h < 21 ]]; then
...
fi
The characters which make up the [[ delimiter cannot be separated by whitespace (to the best of my knowledge).
The double quotes are mainly for safety (good habit in case $h ends up containing an empty string by mistake, for example) and in theory, the && variant could create two external processes where -a would only create one. (It's theory because [ is probably handled internally in moderns shells, so there is no external process involved.)
Shell scripts are not parsed much, the syntax is more shallow than in many other scripting languages and this creates some complications, but also helps make the shell extremely versatile. The lack of standard, built-in arithmetic operators right from the start is another source of complexity in this case. POSIX attempts to fix some of the issues but historically, different shells have developed different extensions which have then created, as it were, even more different ways to skin a cat.