@@ -109,17 +109,34 @@ public Duration deserialize(JsonParser p, DeserializationContext ctxt) throws IO
109109 throw new IOException ("Duration must be a string, got: " + node .getNodeType ());
110110 }
111111
112- // Parse duration string like "1.000000001s" or "30s"
113112 String delayStr = node .asText ();
114113 if (!delayStr .endsWith ("s" )) {
115114 throw new IOException ("Duration must end with 's' suffix: " + delayStr );
116115 }
117116
117+ String numeric = delayStr .substring (0 , delayStr .length () - 1 ).trim ();
118+ if (numeric .isEmpty ()) {
119+ throw new IOException ("Invalid duration format: " + delayStr );
120+ }
121+ if (numeric .startsWith ("-" )) {
122+ throw new IOException ("Duration must be non-negative: " + delayStr );
123+ }
124+
125+ int dotIdx = numeric .indexOf ('.' );
126+ String secondsPart = dotIdx >= 0 ? numeric .substring (0 , dotIdx ) : numeric ;
127+ String fractionPart = dotIdx >= 0 ? numeric .substring (dotIdx + 1 ) : "" ;
128+
129+ if (fractionPart .length () > 9 ) {
130+ throw new IOException ("Fractional seconds precision exceeds nanoseconds: " + delayStr );
131+ }
132+
133+ String fractionPadded =
134+ fractionPart .isEmpty () ? "" : (fractionPart + "000000000" ).substring (0 , 9 );
135+
118136 try {
119- String secondsStr = delayStr .substring (0 , delayStr .length () - 1 );
120- double seconds = Double .parseDouble (secondsStr );
121- long nanos = (long ) (seconds * 1_000_000_000 );
122- return Duration .ofNanos (nanos );
137+ long seconds = secondsPart .isEmpty () ? 0L : Long .parseLong (secondsPart );
138+ long nanos = fractionPadded .isEmpty () ? 0L : Long .parseLong (fractionPadded );
139+ return Duration .ofSeconds (seconds , nanos );
123140 } catch (NumberFormatException e ) {
124141 throw new IOException ("Invalid duration format: " + delayStr , e );
125142 }
0 commit comments