Skip to content

Commit 0a2bbee

Browse files
committed
Remove ints allocation
1 parent adf54cb commit 0a2bbee

2 files changed

Lines changed: 36 additions & 46 deletions

File tree

‎src/core/IronPython.Modules/time.cs‎

Lines changed: 27 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public static string asctime(CodeContext/*!*/ context)
9696
=> AscTimeFormat(DateTime.Now);
9797

9898
public static string asctime(CodeContext/*!*/ context, [NotNone] PythonTuple time)
99-
=> AscTimeFormat(GetDateTimeFromTupleNoDst(context, time));
99+
=> AscTimeFormat(GetDateTimeFromTuple(time, out _));
100100

101101
public static double clock() {
102102
InitStopWatch();
@@ -163,25 +163,23 @@ public static PythonTuple gmtime(object? seconds) {
163163
}
164164

165165
public static double mktime(CodeContext/*!*/ context, [NotNone] PythonTuple localTime) {
166-
DateTime raw = GetDateTimeFromTupleNoDst(context, localTime, out int[]? ints);
166+
DateTime raw = GetDateTimeFromTuple(localTime, out int isDst);
167167
TimeZoneInfo tz = TimeZoneInfo.Local;
168168
if (tz.IsAmbiguousTime(raw)) {
169169
// raw occurs twice (once under daylight, once under standard). Resolve directly from the
170170
// ambiguous offset pair rather than going through RemoveDst+GetStandardOffset: raw can sit
171171
// exactly on an AdjustmentRule's date boundary (e.g. a jurisdiction abolishing DST), where
172172
// date-only rule matching can't tell which side of the transition the shifted result landed on.
173-
bool preferDaylight = ints is null || ints[IsDaylightSavingsIndex] != 0;
173+
bool preferDaylight = isDst != 0;
174174
var offsets = tz.GetAmbiguousTimeOffsets(raw);
175175
return TicksToTimestamp((raw - (preferDaylight ? offsets.Max() : offsets.Min())).Ticks);
176176
}
177177

178-
DateTime res = raw;
179-
if (ints != null) {
180-
switch (ints[IsDaylightSavingsIndex]) {
181-
case -1: res = RemoveDst(raw); break;
182-
case 1: res = RemoveDst(raw, true); break;
183-
}
184-
}
178+
DateTime res = isDst switch {
179+
0 => raw,
180+
< 0 => RemoveDst(raw),
181+
_ => RemoveDst(raw, true),
182+
};
185183
return TicksToTimestamp((res - GetStandardOffset(res)).Ticks);
186184
}
187185

@@ -190,7 +188,7 @@ public static string strftime(CodeContext/*!*/ context, [NotNone] string format)
190188
}
191189

192190
public static string strftime(CodeContext/*!*/ context, [NotNone] string format, [NotNone] PythonTuple dateTime) {
193-
return strftime(context, format, GetDateTimeFromTupleNoDst(context, dateTime), null, TimeZoneInfo.Local, errorOnF: true);
191+
return strftime(context, format, GetDateTimeFromTuple(dateTime, out _), null, TimeZoneInfo.Local, errorOnF: true);
194192
}
195193

196194
public static object? strptime(CodeContext/*!*/ context, [NotNone] string @string) {
@@ -473,46 +471,30 @@ internal static struct_time GetDateTimeTuple(DateTime dt, bool dstMode) {
473471
return new struct_time(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, Weekday(dt), dt.DayOfYear, dstMode ? 1 : 0);
474472
}
475473

476-
private static DateTime GetDateTimeFromTupleNoDst(CodeContext context, PythonTuple t) {
477-
return GetDateTimeFromTupleNoDst(context, t, out _);
478-
}
479-
480-
private static DateTime GetDateTimeFromTupleNoDst(CodeContext context, PythonTuple t, out int[]? ints) {
481-
if (t == null) {
482-
ints = null;
483-
return DateTime.Now;
484-
}
485-
486-
ints = ValidateDateTimeTuple(context, t);
474+
private static int ToInt32(object? o)
475+
=> Converter.TryConvertToIndex(o, out int i) ? i : throw PythonOps.TypeErrorForUnIndexableObject(o);
487476

488-
var month = ints[MonthIndex];
489-
if (month == 0) month = 1;
490-
var day = ints[DayIndex];
491-
if (day == 0) day = 1;
492-
493-
return new DateTime(ints[YearIndex], month, day, ints[HourIndex], ints[MinuteIndex], ints[SecondIndex]);
494-
}
495-
496-
private static int[] ValidateDateTimeTuple(CodeContext/*!*/ context, PythonTuple t) {
477+
private static DateTime GetDateTimeFromTuple(PythonTuple t, out int isDst) {
497478
if (t.__len__() != MaxIndex) throw PythonOps.TypeError("expected tuple of length {0}", MaxIndex);
498479

499-
int[] ints = new int[MaxIndex];
500-
for (int i = 0; i < MaxIndex; i++) {
501-
ints[i] = context.LanguageContext.ConvertToInt32(t[i]);
502-
}
480+
var year = ToInt32(t[YearIndex]);
481+
var month = ToInt32(t[MonthIndex]);
482+
var day = ToInt32(t[DayIndex]);
483+
var hour = ToInt32(t[HourIndex]);
484+
var minute = ToInt32(t[MinuteIndex]);
485+
var second = ToInt32(t[SecondIndex]);
486+
var weekday = ToInt32(t[WeekdayIndex]);
487+
ToInt32(t[DayOfYearIndex]); // validate
488+
isDst = ToInt32(t[IsDaylightSavingsIndex]);
503489

504-
int year = ints[YearIndex];
505-
if (year >= 0 && year <= 99) {
506-
if (year > 68) {
507-
year += 1900;
508-
} else {
509-
year += 2000;
510-
}
511-
}
512490
if (year < DateTime.MinValue.Year) throw PythonOps.ValueError("year is too low");
513491
if (year > DateTime.MaxValue.Year) throw PythonOps.ValueError("year is too high");
514-
if (ints[WeekdayIndex] < 0 || ints[WeekdayIndex] >= 7) throw PythonOps.ValueError("day of week is outside of 0-6 range");
515-
return ints;
492+
if (weekday < 0 || weekday >= 7) throw PythonOps.ValueError("day of week is outside of 0-6 range");
493+
494+
if (month == 0) month = 1;
495+
if (day == 0) day = 1;
496+
497+
return new DateTime(year, month, day, hour, minute, second);
516498
}
517499

518500
[MemberNotNull(nameof(sw))]

‎tests/suite/modules/system_related/test_time.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import os
77
import time
88

9-
from iptest import IronPythonTestCase, is_cli, run_test
9+
from iptest import IronPythonTestCase, is_cli, is_windows, run_test
1010

1111
class TimeTest(IronPythonTestCase):
1212
def test_strftime(self):
@@ -194,5 +194,13 @@ def test_asctime(self):
194194
self.assertEqual(time.asctime((2009, 9, 4, 14, 57, 11, 4, 247, 1)), 'Fri Sep 4 14:57:11 2009')
195195
self.assertEqual(time.asctime((2009, 9, 4, 14, 57, 11, 4, 247, -1)), 'Fri Sep 4 14:57:11 2009')
196196

197+
def test_year_lt_100(self):
198+
t = (50, 7, 1, 12, 0, 0, 2, 182, -1)
199+
if is_cli or not is_windows:
200+
# years below 100 are taken literally and not mapped to 19xx/20xx
201+
self.assertEqual(time.localtime(time.mktime(t))[:6], t[:6])
202+
else:
203+
self.assertRaises(OverflowError, time.mktime, t)
204+
197205

198206
run_test(__name__)

0 commit comments

Comments
 (0)