From 12a92f09527f34696cf3bf5d6bdc9f119e7ea591 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 6 Aug 2026 10:20:38 +0200 Subject: [PATCH] Fix using UTC timezone from interop before initializing datetime Fixes #1065 --- .../graal/python/test/interop/HostInteropTest.java | 12 ++++++++++++ .../builtins/modules/datetime/DateBuiltins.java | 6 +----- .../builtins/modules/datetime/DateTimeBuiltins.java | 6 +----- .../modules/datetime/DatetimeModuleBuiltins.java | 6 +++--- .../builtins/modules/datetime/TimeBuiltins.java | 6 +----- .../builtins/modules/datetime/TimeDeltaBuiltins.java | 5 +---- .../builtins/modules/datetime/TimeZoneBuiltins.java | 6 +----- 7 files changed, 20 insertions(+), 27 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/interop/HostInteropTest.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/interop/HostInteropTest.java index 4d54def051..fc53a30338 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/interop/HostInteropTest.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/interop/HostInteropTest.java @@ -48,9 +48,12 @@ import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalTime; import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Date; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Value; @@ -79,6 +82,15 @@ public void tearDown() { public static int TEST_FIELD = 32; + @Test + public void testJavaTemporalStrWithoutImportingDatetime() { + Value strFunction = context.eval("python", "str"); + assertEquals("1970-01-01 00:00:00+00:00", strFunction.execute(new Date(0)).asString()); + assertEquals("1970-01-01 00:00:00+00:00", strFunction.execute(Instant.EPOCH).asString()); + ZonedDateTime zonedDateTime = ZonedDateTime.of(2000, 1, 2, 3, 4, 5, 0, ZoneId.of("UTC")); + assertEquals("2000-01-02 03:04:05+00:00", strFunction.execute(zonedDateTime).asString()); + } + @Test public void testStaticMembers() { int oldValue = TEST_FIELD; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateBuiltins.java index 7b8145e8bb..1c6f83a063 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateBuiltins.java @@ -51,10 +51,8 @@ import static com.oracle.graal.python.nodes.BuiltinNames.T_MAX; import static com.oracle.graal.python.nodes.BuiltinNames.T_MIN; import static com.oracle.graal.python.nodes.BuiltinNames.T_RESOLUTION; -import static com.oracle.graal.python.nodes.BuiltinNames.T__DATETIME; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___FORMAT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REDUCE__; -import static com.oracle.graal.python.nodes.StringLiterals.T_DATE; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -89,7 +87,6 @@ import com.oracle.graal.python.builtins.objects.bytes.PBytes; import com.oracle.graal.python.builtins.objects.bytes.PBytesLike; import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; -import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; import com.oracle.graal.python.builtins.objects.type.TpSlots; @@ -154,10 +151,9 @@ public void postInitialize(Python3Core core) { PythonLanguage language = core.getLanguage(); - PythonModule datetimeModule = core.lookupBuiltinModule(T__DATETIME); - PythonBuiltinClass self = (PythonBuiltinClass) datetimeModule.getAttribute(T_DATE); final var dateType = PythonBuiltinClassType.PDate; final var dateShape = dateType.getInstanceShape(language); + PythonBuiltinClass self = core.lookupType(dateType); final var minDate = new PDate(dateType, dateShape, MIN_YEAR, 1, 1); self.setAttribute(T_MIN, minDate); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateTimeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateTimeBuiltins.java index 2d76ce7f4b..ccdaba3ea8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateTimeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateTimeBuiltins.java @@ -49,13 +49,11 @@ import static com.oracle.graal.python.nodes.BuiltinNames.T_MAX; import static com.oracle.graal.python.nodes.BuiltinNames.T_MIN; import static com.oracle.graal.python.nodes.BuiltinNames.T_RESOLUTION; -import static com.oracle.graal.python.nodes.BuiltinNames.T__DATETIME; import static com.oracle.graal.python.nodes.ErrorMessages.OBJ_CANNOT_BE_INTERPRETED_AS_INTEGER; import static com.oracle.graal.python.nodes.ErrorMessages.WARN_DEPRECATED_UTCFROMTIMESTAMP; import static com.oracle.graal.python.nodes.ErrorMessages.WARN_DEPRECATED_UTCNOW; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REDUCE_EX__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REDUCE__; -import static com.oracle.graal.python.nodes.StringLiterals.T_DATETIME; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -97,7 +95,6 @@ import com.oracle.graal.python.builtins.objects.bytes.PBytes; import com.oracle.graal.python.builtins.objects.bytes.PBytesLike; import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; -import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; import com.oracle.graal.python.builtins.objects.type.TpSlots; @@ -178,10 +175,9 @@ public void postInitialize(Python3Core core) { PythonLanguage language = core.getLanguage(); - PythonModule datetimeModule = core.lookupBuiltinModule(T__DATETIME); - PythonBuiltinClass self = (PythonBuiltinClass) datetimeModule.getAttribute(T_DATETIME); final var dateTimeType = PythonBuiltinClassType.PDateTime; final var dateTimeShape = dateTimeType.getInstanceShape(language); + PythonBuiltinClass self = core.lookupType(dateTimeType); final var min = new PDateTime(dateTimeType, dateTimeShape, MIN_YEAR, 1, 1, 0, 0, 0, 0, null, 0); self.setAttribute(T_MIN, min); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DatetimeModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DatetimeModuleBuiltins.java index 970d1a3284..a51329f0a2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DatetimeModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DatetimeModuleBuiltins.java @@ -42,7 +42,6 @@ import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError; -import static com.oracle.graal.python.nodes.BuiltinNames.T_TIMEZONE; import static com.oracle.graal.python.nodes.BuiltinNames.T_UTC; import static com.oracle.graal.python.nodes.BuiltinNames.T__DATETIME; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -76,7 +75,8 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; -@CoreFunctions(defineModule = "_datetime") +// Initialized so that the module state is available for host temporal object interop +@CoreFunctions(defineModule = "_datetime", isEager = true) public class DatetimeModuleBuiltins extends PythonBuiltins { static final StructSequence.BuiltinTypeDescriptor ISO_CALENDAR_DATE = new StructSequence.BuiltinTypeDescriptor( @@ -113,7 +113,7 @@ public void postInitialize(Python3Core core) { super.postInitialize(core); PythonModule self = core.lookupBuiltinModule(T__DATETIME); - PythonBuiltinClass timeZoneClass = (PythonBuiltinClass) self.getAttribute(T_TIMEZONE); + PythonBuiltinClass timeZoneClass = core.lookupType(PythonBuiltinClassType.PTimezone); Object utcObject = timeZoneClass.getAttribute(TimeZoneBuiltins.T_UTC_ATTRIBUTE); // if by some reason datetime.timezone.utc attribute isn't set yet diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeBuiltins.java index 9bbda9ebdc..131a739eec 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeBuiltins.java @@ -45,8 +45,6 @@ import static com.oracle.graal.python.nodes.BuiltinNames.T_MAX; import static com.oracle.graal.python.nodes.BuiltinNames.T_MIN; import static com.oracle.graal.python.nodes.BuiltinNames.T_RESOLUTION; -import static com.oracle.graal.python.nodes.BuiltinNames.T_TIME; -import static com.oracle.graal.python.nodes.BuiltinNames.T__DATETIME; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___FORMAT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REDUCE_EX__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REDUCE__; @@ -75,7 +73,6 @@ import com.oracle.graal.python.builtins.objects.bytes.PBytes; import com.oracle.graal.python.builtins.objects.bytes.PBytesLike; import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; -import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; import com.oracle.graal.python.builtins.objects.type.TpSlots; @@ -139,10 +136,9 @@ public void postInitialize(Python3Core core) { PythonLanguage language = core.getLanguage(); - PythonModule datetimeModule = core.lookupBuiltinModule(T__DATETIME); - PythonBuiltinClass self = (PythonBuiltinClass) datetimeModule.getAttribute(T_TIME); final var timeType = PythonBuiltinClassType.PTime; final var timeShape = timeType.getInstanceShape(language); + PythonBuiltinClass self = core.lookupType(timeType); final var min = new PTime(timeType, timeShape, 0, 0, 0, 0, null, 0); self.setAttribute(T_MIN, min); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeDeltaBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeDeltaBuiltins.java index f3296914da..3b16516b7d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeDeltaBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeDeltaBuiltins.java @@ -46,7 +46,6 @@ import static com.oracle.graal.python.nodes.BuiltinNames.T_MAX; import static com.oracle.graal.python.nodes.BuiltinNames.T_MIN; import static com.oracle.graal.python.nodes.BuiltinNames.T_RESOLUTION; -import static com.oracle.graal.python.nodes.BuiltinNames.T__DATETIME; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REDUCE__; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -67,7 +66,6 @@ import com.oracle.graal.python.builtins.objects.PNotImplemented; import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; import com.oracle.graal.python.builtins.objects.ints.PInt; -import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; import com.oracle.graal.python.builtins.objects.type.TpSlots; @@ -131,10 +129,9 @@ public void postInitialize(Python3Core core) { PythonLanguage language = core.getLanguage(); - PythonModule datetimeModule = core.lookupBuiltinModule(T__DATETIME); - PythonBuiltinClass self = (PythonBuiltinClass) datetimeModule.getAttribute(T_TIMEDELTA); final var timeDeltaType = PythonBuiltinClassType.PTimeDelta; final var timeDeltaShape = timeDeltaType.getInstanceShape(language); + PythonBuiltinClass self = core.lookupType(timeDeltaType); final var min = new PTimeDelta(timeDeltaType, timeDeltaShape, -999999999, 0, 0); self.setAttribute(T_MIN, min); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeZoneBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeZoneBuiltins.java index 4843e60157..daa3d01318 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeZoneBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TimeZoneBuiltins.java @@ -44,9 +44,7 @@ import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError; import static com.oracle.graal.python.nodes.BuiltinNames.T_MAX; import static com.oracle.graal.python.nodes.BuiltinNames.T_MIN; -import static com.oracle.graal.python.nodes.BuiltinNames.T_TIMEZONE; import static com.oracle.graal.python.nodes.BuiltinNames.T_UTC; -import static com.oracle.graal.python.nodes.BuiltinNames.T__DATETIME; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___GETINITARGS__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REPR__; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; @@ -65,7 +63,6 @@ import com.oracle.graal.python.builtins.PythonBuiltins; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PNotImplemented; -import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.str.PString; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; import com.oracle.graal.python.builtins.objects.type.TpSlots; @@ -115,12 +112,11 @@ public void postInitialize(Python3Core core) { PythonLanguage language = core.getLanguage(); - PythonModule datetimeModule = core.lookupBuiltinModule(T__DATETIME); - PythonBuiltinClass self = (PythonBuiltinClass) datetimeModule.getAttribute(T_TIMEZONE); var timeDeltaType = PythonBuiltinClassType.PTimeDelta; var timeDeltaShape = timeDeltaType.getInstanceShape(language); var timezoneType = PythonBuiltinClassType.PTimezone; var timezoneShape = timezoneType.getInstanceShape(language); + PythonBuiltinClass self = core.lookupType(timezoneType); // -(23 hours, 59 minutes) var timeDeltaMin = new PTimeDelta(timeDeltaType, timeDeltaShape, -1, 60, 0);