You have to be a little careful with GFS data because it can get pretty confusing with the timing (as you have already seen). First, the GFS forecast is initialized 4 times a day (at 00, 06, 12, 18 hours GMT) so you get 4 forecasts per day. Next, GFS forecast interval for an individual forecast is hourly for the first 5 days then goes to 3-hour intervals up to day 10 then goes to 12-hour interval for the rest up to 16 days as shown in the returned data from your example. So, theoretically you will get 60 (24+18+12+6) images per day with different forecast times if you keep track of all the timing.
However, Earth Engine does not keep track of all of the timing for you. If you look at the metadata, you will see that the system:time_start
is equal to the creation_time
(i.e. initialization time). So, when you use .filterDate()
in EE (which uses the system:time_start
property internally for filtering) you only filter by the day that the forecast was created (all the forecast initialization and forecast hours) and you get (5*24+5*8+6*2)*4 which equals the 688 images from your example.
Hopefully that helps make a little more sense on how the data is structured in terms of time and now we can use that understanding to start filtering. Here is an example getting a single day from different forecasts initializations:
var data_collection = ee.ImageCollection("NOAA/GFS0P25");
// date that we want to focus on
var forecast_date = ee.Date('2019-03-04')
// get 00Z initialization for the whole day
var forecast00 = data_collection.filterDate(forecast_date,forecast_date.advance(6,'hour'))
.filter(ee.Filter.lt('forecast_time',forecast_date.advance(1,'day').millis()))
print('00Z initialization:',forecast00)
// get 06Z initialization for the rest of the day
var forecast06 = data_collection.filterDate(forecast_date.advance(6,'hour'),forecast_date.advance(12,'hour'))
.filter(ee.Filter.lt('forecast_time',forecast_date.advance(1,'day').millis()))
print('06Z initialization:',forecast06)
// get 12Z initialization for the rest of the day
var forecast12 = data_collection.filterDate(forecast_date.advance(12,'hour'),forecast_date.advance(18,'hour'))
.filter(ee.Filter.lt('forecast_time',forecast_date.advance(1,'day').millis()))
print('12Z initialization:',forecast12)
// get 18Z initialization for the rest of the day
var forecast18 = data_collection.filterDate(forecast_date.advance(18,'hour'),forecast_date.advance(24,'hour'))
.filter(ee.Filter.lt('forecast_time',forecast_date.advance(1,'day').millis()))
print('18Z initialization:',forecast18)
As you can see from the example, the .filterDate()
is done on 6-hour intervals to get a specific forecast initialization, then the collection is filtered by the forecast time (within the date of interest). I hope this helps shed some light on the GFS data in Earth Engine. There are other ways to do the filtering based on the properties but this is a good start.
FYI: The GFS data has global coverage so using .filterBounds()
has no effect on reducing the number of images in the collection.