@Override
  public int[] getForecastTimeIntervalOffset(Grib2Record gr) {
    Grib2Pds pds = gr.getPDS();
    if (!pds.isTimeInterval()) {
      return null;
    }

    // LOOK this is hack for CFSR monthly combobulation
    // see http://rda.ucar.edu/datasets/ds093.2/#docs/time_ranges.html

    int statType = pds.getOctet(47);
    int n = pds.getInt4StartingAtOctet(50);
    int p2 = pds.getInt4StartingAtOctet(55);
    int p2mp1 = pds.getInt4StartingAtOctet(62);

    int p1 = p2 - p2mp1;
    int start, end;

    switch (statType) {
      case 193:
        start = p1;
        end = p1 + n * p2;
        break;
      case 194:
        start = 0;
        end = n * p2;
        break;
      case 195:
      case 204:
      case 205:
        start = p1;
        end = p2;
        break;
      default:
        throw new IllegalArgumentException("unknown statType " + statType);
    }

    return new int[]{start, end};
  }
@ Override public int [ ] getForecastTimeIntervalOffset ( Grib2Record gr ) { Grib2Pds pds = gr . getPDS ( ) ; if ( ! pds . isTimeInterval ( ) ) { return null ; } int statType = pds . getOctet ( 47 ) ; int n = pds . getInt4StartingAtOctet ( 50 ) ; int p2 = pds . getInt4StartingAtOctet ( 55 ) ; int p2mp1 = pds . getInt4StartingAtOctet ( 62 ) ; int p1 = p2 - p2mp1 ; int start , end ; switch ( statType ) { case 193 : start = p1 ; end = p1 + n * p2 ; break ; case 194 : start = 0 ; end = n * p2 ; break ; case 195 : case 204 : case 205 : start = p1 ; end = p2 ; break ; default : throw new IllegalArgumentException ( "unknown statType " + statType ) ; } return new int [ ] { start , end } ; }
Reference time is the start time of the first forecast, other forecasts at 6-hour intervals. Number in Ave = number of forecast used