1717package com .google .cloud .bigquery .jdbc ;
1818
1919import com .google .common .base .Strings ;
20+ import java .math .BigDecimal ;
21+ import java .math .RoundingMode ;
2022import java .sql .Date ;
2123import java .sql .Time ;
2224import java .sql .Timestamp ;
@@ -143,45 +145,34 @@ public static Timestamp boxTimestamp(String val) {
143145 }
144146 }
145147
148+ public static Instant parseEpochDecimalToInstant (String epochDecimal ) {
149+ if (epochDecimal == null ) {
150+ return null ;
151+ }
152+ BigDecimal bd = new BigDecimal (epochDecimal );
153+ long seconds = bd .setScale (0 , RoundingMode .FLOOR ).longValue ();
154+ long nanos =
155+ bd .subtract (BigDecimal .valueOf (seconds ))
156+ .movePointRight (9 )
157+ .setScale (0 , RoundingMode .DOWN )
158+ .longValue ();
159+ return Instant .ofEpochSecond (seconds , nanos );
160+ }
161+
146162 public static String formatTimestampString (String epochDecimal , boolean enableTimestampPicos ) {
147163 if (epochDecimal == null ) {
148164 return null ;
149165 }
150166
151- int dotIdx = epochDecimal . indexOf ( '.' );
152- long seconds ;
153- String fraction ;
167+ BigDecimal bd = new BigDecimal ( epochDecimal );
168+ long seconds = bd . setScale ( 0 , RoundingMode . FLOOR ). longValue () ;
169+ BigDecimal fractionalSeconds = bd . subtract ( BigDecimal . valueOf ( seconds )) ;
154170
155- if (dotIdx == -1 ) {
156- seconds = Long .parseLong (epochDecimal );
157- fraction = "000000" ;
158- } else {
159- boolean isNegative = epochDecimal .startsWith ("-" );
160- long wholeSeconds = Long .parseLong (epochDecimal .substring (0 , dotIdx ));
161- fraction = epochDecimal .substring (dotIdx + 1 );
162-
163- if (!enableTimestampPicos && fraction .length () > 6 ) {
164- fraction = fraction .substring (0 , 6 );
165- }
166- fraction = Strings .padEnd (fraction , 6 , '0' );
171+ int originalScale = bd .scale () > 0 ? bd .scale () : 0 ;
172+ int scale = enableTimestampPicos ? Math .max (6 , Math .min (12 , originalScale )) : 6 ;
167173
168- if (isNegative ) {
169- long fracVal = Long .parseLong (fraction );
170- if (fracVal > 0 ) {
171- int len = fraction .length ();
172- long divisor = 1 ;
173- for (int i = 0 ; i < len ; i ++) {
174- divisor *= 10 ;
175- }
176- seconds = wholeSeconds - 1 ;
177- fraction = Strings .padStart (Long .toString (divisor - fracVal ), len , '0' );
178- } else {
179- seconds = wholeSeconds ;
180- }
181- } else {
182- seconds = wholeSeconds ;
183- }
184- }
174+ String fraction =
175+ fractionalSeconds .setScale (scale , RoundingMode .DOWN ).toPlainString ().substring (2 );
185176
186177 Instant instant = Instant .ofEpochSecond (seconds );
187178 return UTC_FORMATTER .format (instant ) + "." + fraction ;
@@ -198,31 +189,36 @@ public static String formatTimestampStringFromMicroseconds(long microseconds) {
198189
199190 public static String formatTimestampStringFromIso (
200191 String isoString , boolean enableTimestampPicos ) {
201- String result = isoString ;
192+ if (isoString == null ) {
193+ return null ;
194+ }
202195
203- if (result .endsWith ("Z" )) {
204- result = result .substring (0 , result .length () - 1 );
205- } else if (result .endsWith (" UTC" )) {
206- result = result .substring (0 , result .length () - 4 );
196+ String s = isoString ;
197+ if (s .endsWith (" UTC" )) {
198+ s = s .substring (0 , s .length () - 4 );
199+ } else if (s .endsWith ("Z" )) {
200+ s = s .substring (0 , s .length () - 1 );
207201 }
208202
209- if (result .length () > 10 && result .charAt (10 ) == 'T' ) {
210- result = result .substring (0 , 10 ) + ' ' + result .substring (11 );
203+ if (s .length () > 10 && s .charAt (10 ) == 'T' ) {
204+ s = s .substring (0 , 10 ) + ' ' + s .substring (11 );
211205 }
212206
213- int dotIdx = result .indexOf ('.' );
207+ int dotIdx = s .indexOf ('.' );
214208 if (dotIdx == -1 ) {
215- return result + ".000000" ;
209+ return s + ".000000" ;
216210 }
217211
218- int fractionLen = result .length () - dotIdx - 1 ;
219- if (!enableTimestampPicos && fractionLen > 6 ) {
220- return result .substring (0 , dotIdx + 7 );
221- }
212+ String base = s .substring (0 , dotIdx );
213+ String fraction = s .substring (dotIdx + 1 );
222214
223- if (fractionLen < 6 ) {
224- result = Strings .padEnd (result , result .length () + (6 - fractionLen ), '0' );
215+ int maxScale = enableTimestampPicos ? 12 : 6 ;
216+ if (fraction .length () > maxScale ) {
217+ fraction = fraction .substring (0 , maxScale );
218+ } else if (fraction .length () < 6 ) {
219+ fraction = Strings .padEnd (fraction , 6 , '0' );
225220 }
226- return result ;
221+
222+ return base + "." + fraction ;
227223 }
228224}
0 commit comments