Skip to content

Commit ff012a3

Browse files
committed
convert Temporal.Duration asDuration(), and test
1 parent f926a31 commit ff012a3

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/TemporalInteropToJavaTest.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
import static com.oracle.truffle.js.lang.JavaScriptLanguage.ID;
4545

46+
import java.time.Duration;
4647
import java.time.Instant;
4748
import java.time.LocalDate;
4849
import java.time.LocalTime;
@@ -63,8 +64,7 @@ private static Context getJSContext() {
6364
return JSTest.newContextBuilder(ID).option("js.temporal", "true").build();
6465
}
6566

66-
// Calendar, Duration, PlainMonthDay, PlainYearMonth cannot be converted to Instant, Date or
67-
// Time
67+
// Calendar, PlainMonthDay, PlainYearMonth cannot be converted to Instant, Date or Time
6868

6969
@Test
7070
public void testInstant() {
@@ -198,4 +198,30 @@ public void testZonedDateTime() {
198198
Assert.assertEquals("Europe/Vienna", zid.getId());
199199
}
200200
}
201+
202+
@Test
203+
public void testDuration() {
204+
try (Context ctx = getJSContext()) {
205+
Value val = ctx.eval(ID, "Temporal.Duration.from('PT2H3M4.987654321S');");
206+
Duration dur = val.asDuration();
207+
208+
long expectedSeconds = 2 * 60 * 60 + 3 * 60 + 4;
209+
long expectedNanos = 987654321;
210+
Assert.assertEquals(0, dur.toDays());
211+
Assert.assertEquals(4, dur.toSecondsPart());
212+
Assert.assertEquals(expectedSeconds, dur.toSeconds());
213+
Assert.assertEquals(expectedNanos, dur.toNanosPart());
214+
Assert.assertEquals(expectedSeconds * 1_000_000_000 + expectedNanos, dur.toNanos());
215+
216+
// invalid duration; java.time.Duration does not accept units larger or equals to DAY
217+
val = ctx.eval(ID, "Temporal.Duration.from('P1Y');");
218+
Assert.assertFalse(val.isDuration());
219+
val = ctx.eval(ID, "Temporal.Duration.from('P2M');");
220+
Assert.assertFalse(val.isDuration());
221+
val = ctx.eval(ID, "Temporal.Duration.from('P3W');");
222+
Assert.assertFalse(val.isDuration());
223+
val = ctx.eval(ID, "Temporal.Duration.from('P4D');");
224+
Assert.assertFalse(val.isDuration());
225+
}
226+
}
201227
}

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDurationObject.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,18 @@
4040
*/
4141
package com.oracle.truffle.js.runtime.builtins.temporal;
4242

43+
import java.time.Duration;
44+
45+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
46+
import com.oracle.truffle.api.interop.InteropLibrary;
47+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
48+
import com.oracle.truffle.api.library.ExportLibrary;
49+
import com.oracle.truffle.api.library.ExportMessage;
4350
import com.oracle.truffle.api.object.Shape;
51+
import com.oracle.truffle.js.runtime.JSRuntime;
4452
import com.oracle.truffle.js.runtime.objects.JSNonProxyObject;
4553

54+
@ExportLibrary(InteropLibrary.class)
4655
public class JSTemporalDurationObject extends JSNonProxyObject {
4756

4857
private final double years;
@@ -110,4 +119,31 @@ public double getMicroseconds() {
110119
public double getNanoseconds() {
111120
return nanoseconds;
112121
}
122+
123+
@ExportMessage
124+
final boolean isDuration() {
125+
// note: java.time.Duration only considers DAYS, while JS Temporal also has W, M, Y.
126+
// due to vague DAYS support in Java, we disallow conversion when any of D, W, M, Y is != 0.
127+
return years == 0 && months == 0 && weeks == 0 && days == 0 && JSRuntime.doubleIsRepresentableAsLong(calcSeconds()) && JSRuntime.doubleIsRepresentableAsLong(calcNanoseconds());
128+
}
129+
130+
@ExportMessage
131+
@TruffleBoundary
132+
final Duration asDuration() throws UnsupportedMessageException {
133+
if (!isDuration()) {
134+
throw UnsupportedMessageException.create();
135+
}
136+
double sec = calcSeconds();
137+
double nanos = calcNanoseconds();
138+
Duration dur = Duration.ofSeconds((long) sec, (long) nanos);
139+
return dur;
140+
}
141+
142+
private double calcNanoseconds() {
143+
return nanoseconds + microseconds * 1_000 + milliseconds * 1_000_000;
144+
}
145+
146+
private double calcSeconds() {
147+
return seconds + minutes * 60 + hours * 60 * 60;
148+
}
113149
}

0 commit comments

Comments
 (0)