Skip to content

Commit c40695e

Browse files
authored
Merge pull request #483 from zhenlineo/1.6-duration
Print ISO standard format in `IsoDuration#toString()`
2 parents e2b98bf + 8e6dd4c commit c40695e

File tree

7 files changed

+90
-15
lines changed

7 files changed

+90
-15
lines changed

driver/src/main/java/org/neo4j/driver/internal/InternalIsoDuration.java

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@
3838
public class InternalIsoDuration implements IsoDuration
3939
{
4040
private static final List<TemporalUnit> SUPPORTED_UNITS = unmodifiableList( asList( MONTHS, DAYS, SECONDS, NANOS ) );
41+
private static final InternalIsoDuration ZERO = new InternalIsoDuration( 0, 0, 0, 0 );
42+
public static final long NANOS_PER_SECOND = 1_000_000_000L;
4143

4244
private final long months;
4345
private final long days;
4446
private final long seconds;
45-
private final long nanoseconds;
47+
private final int nanoseconds;
4648

4749
public InternalIsoDuration( Period period )
4850
{
@@ -54,14 +56,19 @@ public InternalIsoDuration( Duration duration )
5456
this( 0, 0, duration.getSeconds(), duration.getNano() );
5557
}
5658

57-
public InternalIsoDuration( long months, long days, long seconds, long nanoseconds )
59+
public InternalIsoDuration( long months, long days, long seconds, int nanoseconds )
5860
{
5961
this.months = months;
6062
this.days = days;
6163
this.seconds = seconds;
6264
this.nanoseconds = nanoseconds;
6365
}
6466

67+
public InternalIsoDuration( Period period, Duration duration )
68+
{
69+
this( period.toTotalMonths(), period.getDays(), duration.getSeconds(), duration.getNano() );
70+
}
71+
6572
@Override
6673
public long months()
6774
{
@@ -81,7 +88,7 @@ public long seconds()
8188
}
8289

8390
@Override
84-
public long nanoseconds()
91+
public int nanoseconds()
8592
{
8693
return nanoseconds;
8794
}
@@ -188,11 +195,65 @@ public int hashCode()
188195
@Override
189196
public String toString()
190197
{
191-
return "Duration{" +
192-
"months=" + months +
193-
", days=" + days +
194-
", seconds=" + seconds +
195-
", nanoseconds=" + nanoseconds +
196-
'}';
198+
// print the duration in iso standard format.
199+
if ( this.equals( ZERO ) )
200+
{
201+
return "PT0S"; // no need to allocate a string builder if we know the result
202+
}
203+
StringBuilder str = new StringBuilder().append( "P" );
204+
append( str, months / 12, 'Y' );
205+
append( str, months % 12, 'M' );
206+
append( str, days / 7, 'W' );
207+
append( str, days % 7, 'D' );
208+
if ( seconds != 0 || nanoseconds != 0 )
209+
{
210+
str.append( 'T' );
211+
long s = seconds % 3600;
212+
append( str, seconds / 3600, 'H' );
213+
append( str, s / 60, 'M' );
214+
s %= 60;
215+
if ( s != 0 )
216+
{
217+
str.append( s );
218+
if ( nanoseconds != 0 )
219+
{
220+
nanos( str );
221+
}
222+
str.append( 'S' );
223+
}
224+
else if ( nanoseconds != 0 )
225+
{
226+
if ( nanoseconds < 0 )
227+
{
228+
str.append( '-' );
229+
}
230+
str.append( '0' );
231+
nanos( str );
232+
str.append( 'S' );
233+
}
234+
}
235+
if ( str.length() == 1 )
236+
{ // this was all zeros (but not ZERO for some reason), ensure well formed output:
237+
str.append( "T0S" );
238+
}
239+
return str.toString();
240+
}
241+
242+
private static void append( StringBuilder str, long quantity, char unit )
243+
{
244+
if ( quantity != 0 )
245+
{
246+
str.append( quantity ).append( unit );
247+
}
248+
}
249+
250+
private void nanos( StringBuilder str )
251+
{
252+
str.append( '.' );
253+
int n = nanoseconds < 0 ? -nanoseconds : nanoseconds;
254+
for ( int mod = (int)NANOS_PER_SECOND; mod > 1 && n > 0; n %= mod )
255+
{
256+
str.append( n / (mod /= 10) );
257+
}
197258
}
198259
}

driver/src/main/java/org/neo4j/driver/internal/messaging/PackStreamMessageFormatV2.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ private Value unpackDuration() throws IOException
320320
long months = unpacker.unpackLong();
321321
long days = unpacker.unpackLong();
322322
long seconds = unpacker.unpackLong();
323-
long nanoseconds = unpacker.unpackLong();
323+
int nanoseconds = Math.toIntExact( unpacker.unpackLong() );
324324
return isoDuration( months, days, seconds, nanoseconds );
325325
}
326326

driver/src/main/java/org/neo4j/driver/v1/Values.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ public static Value value( Duration duration )
323323
return value( new InternalIsoDuration( duration ) );
324324
}
325325

326-
public static Value isoDuration( long months, long days, long seconds, long nanoseconds )
326+
public static Value isoDuration( long months, long days, long seconds, int nanoseconds )
327327
{
328328
return value( new InternalIsoDuration( months, days, seconds, nanoseconds ) );
329329
}

driver/src/main/java/org/neo4j/driver/v1/types/IsoDuration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,5 @@ public interface IsoDuration extends TemporalAmount
5757
*
5858
* @return number of nanoseconds.
5959
*/
60-
long nanoseconds();
60+
int nanoseconds();
6161
}

driver/src/test/java/org/neo4j/driver/internal/InternalIsoDurationTest.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
import static java.time.temporal.ChronoUnit.SECONDS;
3535
import static java.time.temporal.ChronoUnit.YEARS;
3636
import static java.util.Arrays.asList;
37+
import static org.hamcrest.Matchers.equalTo;
3738
import static org.junit.Assert.assertEquals;
39+
import static org.junit.Assert.assertThat;
3840
import static org.junit.Assert.fail;
3941

4042
public class InternalIsoDurationTest
@@ -151,7 +153,19 @@ public void shouldCreateFromDuration()
151153
assertEquals( duration.getNano(), isoDuration.nanoseconds() );
152154
}
153155

154-
private static IsoDuration newDuration( long months, long days, long seconds, long nanoseconds )
156+
@Test
157+
public void toStringShouldPrintInIsoStandardFormat() throws Throwable
158+
{
159+
assertThat( new InternalIsoDuration( 0, 0, 0, 0 ).toString(), equalTo( "PT0S" ) );
160+
assertThat( new InternalIsoDuration( Period.parse( "P356D" ) ).toString(), equalTo( "P50W6D" ) );
161+
assertThat( new InternalIsoDuration( Duration.parse( "PT45S" ) ).toString(), equalTo( "PT45S" ) );
162+
163+
assertThat( new InternalIsoDuration( Period.parse( "P14D" ), Duration.parse( "PT16H12M" ) ).toString(), equalTo( "P2WT16H12M" ) );
164+
assertThat( new InternalIsoDuration( Period.parse( "P5M1D" ), Duration.parse( "PT12H" ) ).toString(), equalTo( "P5M1DT12H" ) );
165+
assertThat( new InternalIsoDuration( Period.parse( "P2W3D" ), Duration.parse( "PT12H" ) ).toString(), equalTo( "P2W3DT12H" ) );
166+
}
167+
168+
private static IsoDuration newDuration( long months, long days, long seconds, int nanoseconds )
155169
{
156170
return new InternalIsoDuration( months, days, seconds, nanoseconds );
157171
}

driver/src/test/java/org/neo4j/driver/internal/value/DurationValueTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public void shouldNotSupportAsLong()
7070
}
7171
}
7272

73-
private static IsoDuration newDuration( long months, long days, long seconds, long nanoseconds )
73+
private static IsoDuration newDuration( long months, long days, long seconds, int nanoseconds )
7474
{
7575
return new InternalIsoDuration( months, days, seconds, nanoseconds );
7676
}

driver/src/test/java/org/neo4j/driver/v1/integration/TemporalTypesIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ private <T> void testSendAndReceiveValue( T value, Function<Value,T> converter )
275275
assertEquals( value, converter.apply( record.get( 0 ) ) );
276276
}
277277

278-
private static IsoDuration newDuration( long months, long days, long seconds, long nanoseconds )
278+
private static IsoDuration newDuration( long months, long days, long seconds, int nanoseconds )
279279
{
280280
return isoDuration( months, days, seconds, nanoseconds ).asIsoDuration();
281281
}

0 commit comments

Comments
 (0)