11package org .opendcs .usgs .waterdata ;
22
33import java .time .Instant ;
4+ import java .time .temporal .ChronoUnit ;
45import java .util .ArrayList ;
56import java .util .HashMap ;
67import java .util .List ;
@@ -33,6 +34,7 @@ public class UsgsWaterDataApi {
3334 * Maximum number of responses the API returns per request
3435 */
3536 static final int PAGE_LIMIT = 50000 ;
37+ static final long MAX_WINDOW_DAYS = 1000 ;
3638
3739 static final String ROOT_URL = "https://api.waterdata.usgs.gov/ogcapi/v0/collections/" ;
3840 static final String LOCATIONS_URL = ROOT_URL + "monitoring-locations/items?f=csv&lang=en-US&limit=50000&offset=0&agency_code=USGS&state_code=%s&site_type_code=%s" ;
@@ -102,17 +104,20 @@ private static List<InstantaneousValue> fetchContinuousValues(String timeSeriesI
102104 return TestSite .generateContinuousValues (startDate , endDate );
103105
104106 List <InstantaneousValue > all = new ArrayList <>();
105- String chunkStart = normalizeToInstant (startDate );
106- String normalizedEnd = normalizeToInstant (endDate );
107+ Instant rangeEnd = Instant . parse ( normalizeToInstant (endDate ) );
108+ Instant chunkStart = Instant . parse ( normalizeToInstant (startDate ) );
107109 Instant lastSeen = null ;
108110 boolean continuation = false ;
109- while (true ) {
110- String url = String . format ( CONTINUOUS_URL_ID , timeSeriesId , chunkStart , normalizedEnd );
111- String csv = WebUtility . getPage ( url );
112- if (csv == null || csv . isBlank ( )) break ;
111+ while (chunkStart . isBefore ( rangeEnd ) ) {
112+ // Cap the request at the API's maximum time envelope.
113+ Instant windowEnd = chunkStart . plus ( MAX_WINDOW_DAYS , ChronoUnit . DAYS );
114+ if (windowEnd . isAfter ( rangeEnd )) windowEnd = rangeEnd ;
113115
114- List <InstantaneousValue > page = CsvFile .fromString (csv ).mapRows (InstantaneousValue ::fromRow );
115- if (page .isEmpty ()) break ;
116+ String url = String .format (CONTINUOUS_URL_ID , timeSeriesId , chunkStart .toString (), windowEnd .toString ());
117+ String csv = WebUtility .getPage (url );
118+ List <InstantaneousValue > page = (csv == null || csv .isBlank ())
119+ ? Collections .emptyList ()
120+ : CsvFile .fromString (csv ).mapRows (InstantaneousValue ::fromRow );
116121
117122 for (int i = 0 ; i < page .size (); i ++) {
118123 InstantaneousValue iv = page .get (i );
@@ -129,12 +134,16 @@ private static List<InstantaneousValue> fetchContinuousValues(String timeSeriesI
129134 all .add (iv );
130135 lastSeen = iv .time ;
131136 }
132-
133- if (page .size () < PAGE_LIMIT ) break ;
134- if (lastSeen == null || chunkStart .equals (lastSeen .toString ())) break ;
135- chunkStart = lastSeen .toString ();
136137 continuation = true ;
137- logger .info ("Continuous query returned a full page; fetching next chunk from " + chunkStart );
138+
139+ if (page .size () >= PAGE_LIMIT && lastSeen != null && lastSeen .isAfter (chunkStart )) {
140+ // Window was truncated at the page limit; resume from its last point.
141+ chunkStart = lastSeen ;
142+ logger .info ("Continuous query returned a full page; fetching next chunk from " + chunkStart );
143+ } else {
144+ // Window exhausted; advance to the next time window.
145+ chunkStart = windowEnd ;
146+ }
138147 }
139148 return all .isEmpty () ? Collections .emptyList () : all ;
140149 }
0 commit comments