Expression wise you could do something like this since 3.16:
To count one specific hour:
array_count(overlay_contains('name_of_pointlayer',"name_of_hourfield"),hour_you_want_to_count)
To create a sorted array of counts, where array position 0 is count of hour 0 and position 6 is count of hour 6:
array_foreach(generate_series(0,23),array_count(overlay_contains('pointlayer',"hour"),@element))
To create a sorted string of counts, where string position 0 is count of hour 0 and position 6 is count of hour 6. Delimiter is semicolon, change that to whatever you want:
array_to_string(array_foreach(generate_series(0,23),array_count(overlay_contains('pointlayer',"hour"),@element)),';')
To create a map/dictionary of hours as keys and counts as values (both as strings). Pretty similar would go for an hstore type:
hstore_to_map(array_to_string(array_foreach(generate_series(0,23),@element||'=>'||array_count(overlay_contains('pointlayer',"hour"),@element))))
to get a value from this map/dictionary as integer, e.g. the count of hour 2:
to_int(hstore_to_map(array_to_string(array_foreach(generate_series(0,23),@element||'=>'||array_count(overlay_contains('pointlayer',"hour"),@element))))['2'])
unfortunately there is no possibility with QGIS expressions to create a dictionary/map with integers as values... that would require a custom Python function.