6767import com .oracle .graal .python .builtins .objects .namespace .PSimpleNamespace ;
6868import com .oracle .graal .python .builtins .objects .tuple .PTuple ;
6969import com .oracle .graal .python .builtins .objects .tuple .StructSequence ;
70+ import com .oracle .graal .python .lib .OsEnvironGetNode ;
7071import com .oracle .graal .python .lib .PyFloatAsDoubleNode ;
7172import com .oracle .graal .python .lib .PyImportImport ;
7273import com .oracle .graal .python .lib .PyLongAsLongNode ;
9091import com .oracle .graal .python .nodes .util .CastToJavaDoubleNode ;
9192import com .oracle .graal .python .runtime .GilNode ;
9293import com .oracle .graal .python .runtime .PythonContext ;
93- import com .oracle .graal .python .runtime .PythonImageBuildOptions ;
9494import com .oracle .graal .python .runtime .object .PFactory ;
9595import com .oracle .graal .python .util .PythonUtils ;
9696import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
112112import com .oracle .truffle .api .nodes .ExplodeLoop ;
113113import com .oracle .truffle .api .nodes .Node ;
114114import com .oracle .truffle .api .strings .TruffleString ;
115+ import com .oracle .truffle .api .strings .TruffleString .ToJavaStringNode ;
115116
116117@ CoreFunctions (defineModule = "time" )
117118public final class TimeModuleBuiltins extends PythonBuiltins {
118119 private static final int DELAY_NANOS = 10 ;
119120 private static final String CTIME_FORMAT = "%s %s %2d %02d:%02d:%02d %d" ;
120121 private static final ZoneId GMT = ZoneId .of ("GMT" );
122+ private static final TruffleString T_TZ = tsLiteral ("TZ" );
121123
122124 private static final StructSequence .BuiltinTypeDescriptor STRUCT_TIME_DESC = new StructSequence .BuiltinTypeDescriptor (
123125 PythonBuiltinClassType .PStructTime ,
@@ -162,32 +164,66 @@ public void initialize(Python3Core core) {
162164 @ Override
163165 public void postInitialize (Python3Core core ) {
164166 super .postInitialize (core );
165- // Should we read TZ env variable?
166- ZoneId defaultZoneId = core .getContext ().getEnv ().getTimeZone ();
167167 ModuleState moduleState = new ModuleState ();
168- moduleState .currentZoneId = defaultZoneId ;
169- moduleState .timeSlept = 0 ;
170168 PythonModule timeModule = core .lookupBuiltinModule (T_TIME );
171169 timeModule .setModuleState (moduleState );
172170
173- TimeZone defaultTimeZone = TimeZone .getTimeZone (defaultZoneId );
174- TruffleString noDaylightSavingZone = toTruffleStringUncached (defaultTimeZone .getDisplayName (false , TimeZone .SHORT ));
175- TruffleString daylightSavingZone = toTruffleStringUncached (defaultTimeZone .getDisplayName (true , TimeZone .SHORT ));
176-
177- timeModule .setAttribute (T_TZNAME , PFactory .createTuple (core .getLanguage (), new Object []{noDaylightSavingZone , daylightSavingZone }));
178- timeModule .setAttribute (T_DAYLIGHT , PInt .intValue (defaultTimeZone .getDSTSavings () != 0 ));
179- timeModule .setAttribute (T_TIMEZONE , defaultTimeZone .getRawOffset () / -1000 );
180- timeModule .setAttribute (T_ALTZONE , (defaultTimeZone .getRawOffset () + defaultTimeZone .getDSTSavings ()) / -1000 );
171+ setGlobalTimeZone (timeModule , core .getLanguage (), core .getContext ());
181172
182173 // register_interop_behavior() for time.struct_time
183174 AbstractImportNode .importModule (T_POLYGLOT_TIME );
184175 }
185176
177+ /**
178+ * Determine and set global time zone (for the current Truffle context). Timezone is based on
179+ * the TZ env variable. Intentionally don't change Java default timezone (with
180+ * {@code TimeZone.setDefault}) because it affects all the contexts.
181+ */
182+ private static void setGlobalTimeZone (PythonModule timeModule , PythonLanguage language , PythonContext context ) {
183+ TruffleString tsTzEnv = OsEnvironGetNode .lookupUncached (T_TZ );
184+
185+ TimeZone timeZone ;
186+ if (tsTzEnv == null ) {
187+ // switch back to the context-specific default timezone
188+ ZoneId zoneId = context .getEnv ().getTimeZone ();
189+ timeZone = TimeZone .getTimeZone (zoneId );
190+ } else {
191+ String tzEnv = ToJavaStringNode .getUncached ().execute (tsTzEnv );
192+ timeZone = TimeZone .getTimeZone (tzEnv );
193+ }
194+
195+ // save in the module state
196+ ModuleState moduleState = timeModule .getModuleState (ModuleState .class );
197+ moduleState .currentZoneId = timeZone .toZoneId ();
198+
199+ // update time module attributes
200+ TruffleString noDaylightSavingZone = toTruffleStringUncached (timeZone .getDisplayName (false , TimeZone .SHORT ));
201+ TruffleString daylightSavingZone = toTruffleStringUncached (timeZone .getDisplayName (true , TimeZone .SHORT ));
202+
203+ timeModule .setAttribute (T_TZNAME , PFactory .createTuple (language , new Object []{noDaylightSavingZone , daylightSavingZone }));
204+ timeModule .setAttribute (T_DAYLIGHT , PInt .intValue (timeZone .getDSTSavings () != 0 ));
205+ timeModule .setAttribute (T_TIMEZONE , timeZone .getRawOffset () / -1000 );
206+ timeModule .setAttribute (T_ALTZONE , (timeZone .getRawOffset () + timeZone .getDSTSavings ()) / -1000 );
207+ }
208+
186209 @ TruffleBoundary
187210 public static double timeSeconds () {
188211 return System .currentTimeMillis () / 1000.0 ;
189212 }
190213
214+ /**
215+ * Return current time zone (that can be changed with time.tzset()). The only correct way to get
216+ * it.
217+ */
218+ public static TimeZone getGlobalTimeZone (PythonContext context ) {
219+ PythonModule timeModule = context .lookupBuiltinModule (T_TIME );
220+
221+ ModuleState moduleState = timeModule .getModuleState (ModuleState .class );
222+ ZoneId zoneId = moduleState .currentZoneId ;
223+
224+ return TimeZone .getTimeZone (zoneId );
225+ }
226+
191227 private static final int TM_YEAR = 0 ; /* year */
192228 private static final int TM_MON = 1 ; /* month */
193229 private static final int TM_MDAY = 2 ; /* day of the month */
@@ -306,23 +342,15 @@ static PTuple gmtime(VirtualFrame frame, Object seconds,
306342 }
307343 }
308344
309- @ Builtin (name = "tzset" )
345+ // time.tzset()
346+ @ Builtin (name = "tzset" , maxNumOfPositionalArgs = 1 , declaresExplicitSelf = true )
310347 @ GenerateNodeFactory
311348 public abstract static class TzSetNode extends PythonBuiltinNode {
312- private static final TruffleString SET_TIMEZONE_ERROR = tsLiteral ("Setting timezone was disallowed." );
313349
314350 @ Specialization
315351 @ TruffleBoundary
316- Object tzset () {
317- if (!PythonImageBuildOptions .WITHOUT_PLATFORM_ACCESS ) {
318- String tzEnv = getContext ().getEnv ().getEnvironment ().get ("TZ" );
319- if (tzEnv == null ) {
320- tzEnv = "" ;
321- }
322- TimeZone .setDefault (TimeZone .getTimeZone (tzEnv ));
323- } else {
324- throw PRaiseNode .raiseStatic (this , PythonBuiltinClassType .AttributeError , SET_TIMEZONE_ERROR );
325- }
352+ Object tzset (PythonModule self ) {
353+ setGlobalTimeZone (self , getLanguage (), getContext ());
326354 return PNone .NONE ;
327355 }
328356 }
@@ -920,7 +948,7 @@ private static TruffleString format(String format, int[] date, TruffleString.Fro
920948 static TruffleString formatTime (PythonModule module , TruffleString format , @ SuppressWarnings ("unused" ) PNone time ,
921949 @ Bind Node inliningTarget ,
922950 @ Shared ("byteIndexOfCp" ) @ Cached TruffleString .ByteIndexOfCodePointNode byteIndexOfCodePointNode ,
923- @ Shared ("ts2js" ) @ Cached TruffleString . ToJavaStringNode toJavaStringNode ,
951+ @ Shared ("ts2js" ) @ Cached ToJavaStringNode toJavaStringNode ,
924952 @ Shared ("js2ts" ) @ Cached TruffleString .FromJavaStringNode fromJavaStringNode ,
925953 @ Exclusive @ Cached PRaiseNode raiseNode ) {
926954 if (byteIndexOfCodePointNode .execute (format , 0 , 0 , format .byteLength (TS_ENCODING ), TS_ENCODING ) >= 0 ) {
@@ -936,7 +964,7 @@ static TruffleString formatTime(VirtualFrame frame, @SuppressWarnings("unused")
936964 @ Cached SequenceStorageNodes .GetInternalObjectArrayNode getArray ,
937965 @ Cached PyNumberAsSizeNode asSizeNode ,
938966 @ Shared ("byteIndexOfCp" ) @ Cached TruffleString .ByteIndexOfCodePointNode byteIndexOfCodePointNode ,
939- @ Shared ("ts2js" ) @ Cached TruffleString . ToJavaStringNode toJavaStringNode ,
967+ @ Shared ("ts2js" ) @ Cached ToJavaStringNode toJavaStringNode ,
940968 @ Shared ("js2ts" ) @ Cached TruffleString .FromJavaStringNode fromJavaStringNode ,
941969 @ Exclusive @ Cached PRaiseNode raiseNode ) {
942970 if (byteIndexOfCodePointNode .execute (format , 0 , 0 , format .byteLength (TS_ENCODING ), TS_ENCODING ) >= 0 ) {
0 commit comments