Make calendar-import performance gates deterministic #1286

Merged
timmy merged 1 commits from timmy/1285-calendar-import-performance-gate into main 2026-08-23 00:32:33 +00:00
2 changed files with 37 additions and 12 deletions

View File

@ -1,5 +1,6 @@
function createWeekCalendarImport() {
const maxBytes=1024*1024;
const zonedInstantFormatters=new Map(),zonePartFormatters=new Map(),supportedTimeZones=new Map();
function clock(value) {
const match=/^(\d{2}):(\d{2})$/.exec(String(value||''));
if(!match)return null;
@ -19,9 +20,11 @@ function createWeekCalendarImport() {
const match=/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})$/.exec(value||'');
if(!match)return null;
try {
const wanted=match.slice(1).map(Number),formatter=new Intl.DateTimeFormat('en-CA',{
const wanted=match.slice(1).map(Number);
if(!zonedInstantFormatters.has(timeZone))zonedInstantFormatters.set(timeZone,new Intl.DateTimeFormat('en-CA',{
timeZone,year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit',second:'2-digit',hourCycle:'h23',
});
}));
const formatter=zonedInstantFormatters.get(timeZone);
let result=Date.UTC(wanted[0],wanted[1]-1,wanted[2],wanted[3],wanted[4],wanted[5]);
for(let attempt=0;attempt<2;attempt+=1) {
const shown=Object.fromEntries(formatter.formatToParts(new Date(result)).map(part=>[part.type,part.value]));
@ -33,15 +36,18 @@ function createWeekCalendarImport() {
}
function supportedTimeZone(timeZone) {
if(!timeZone)return true;
try {new Intl.DateTimeFormat('en-US',{timeZone}).format(0);return true;}
catch(error) {return false;}
if(supportedTimeZones.has(timeZone))return supportedTimeZones.get(timeZone);
try {new Intl.DateTimeFormat('en-US',{timeZone}).format(0);supportedTimeZones.set(timeZone,true);return true;}
catch(error) {supportedTimeZones.set(timeZone,false);return false;}
}
function zoneParts(value,timeZone) {
const date=new Date(value);
if(!timeZone)return {year:date.getFullYear(),month:date.getMonth()+1,day:date.getDate(),weekday:date.getDay(),
hour:date.getHours(),minute:date.getMinutes(),second:date.getSeconds()};
const formatter=new Intl.DateTimeFormat('en-US',{timeZone,year:'numeric',month:'2-digit',day:'2-digit',
hour:'2-digit',minute:'2-digit',second:'2-digit',weekday:'short',hourCycle:'h23'});
if(!zonePartFormatters.has(timeZone))zonePartFormatters.set(timeZone,new Intl.DateTimeFormat('en-US',{
timeZone,year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit',second:'2-digit',weekday:'short',hourCycle:'h23',
}));
const formatter=zonePartFormatters.get(timeZone);
const parts=Object.fromEntries(formatter.formatToParts(date).map(part=>[part.type,part.value]));
return {year:Number(parts.year),month:Number(parts.month),day:Number(parts.day),
weekday:['Sun','Mon','Tue','Wed','Thu','Fri','Sat'].indexOf(parts.weekday),hour:Number(parts.hour),

View File

@ -118,12 +118,11 @@ process.env.TZ='UTC';
const event=`BEGIN:VEVENT\r\nDTSTART;TZID=America/New_York:20000101T090000\r\nDTEND;TZID=America/New_York:20000101T100000\r\nRRULE:FREQ=DAILY\r\nEND:VEVENT\r\n`;
const source='BEGIN:VCALENDAR\\r\\nVERSION:2.0\\r\\n'+event.repeat(80)+'END:VCALENDAR';
const dates=['2026-08-21','2026-08-22','2026-08-23','2026-08-24','2026-08-25','2026-08-26','2026-08-27'];
const started=Date.now();const days=calendarImport.review(source,{dates,workdayStart:'09:00',workdayEnd:'17:00'});
console.log(JSON.stringify({elapsed:Date.now()-started,busy:days.map(day=>day.busy_minutes)}));
const days=calendarImport.review(source,{dates,workdayStart:'09:00',workdayEnd:'17:00'});
console.log(JSON.stringify({busy:days.map(day=>day.busy_minutes)}));
""")
assert result["busy"] == [60] * 7
assert result["elapsed"] < 1000
def test_calendar_import_fast_forwards_historical_weekly_series_to_seven_day_range():
@ -132,12 +131,32 @@ process.env.TZ='UTC';
const event=`BEGIN:VEVENT\r\nDTSTART;TZID=America/New_York:20000101T090000\r\nDTEND;TZID=America/New_York:20000101T100000\r\nRRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;INTERVAL=2\r\nEND:VEVENT\r\n`;
const source='BEGIN:VCALENDAR\\r\\nVERSION:2.0\\r\\n'+event.repeat(80)+'END:VCALENDAR';
const dates=['2026-08-21','2026-08-22','2026-08-23','2026-08-24','2026-08-25','2026-08-26','2026-08-27'];
const started=Date.now();const days=calendarImport.review(source,{dates,workdayStart:'09:00',workdayEnd:'17:00'});
console.log(JSON.stringify({elapsed:Date.now()-started,busy:days.map(day=>day.busy_minutes)}));
const days=calendarImport.review(source,{dates,workdayStart:'09:00',workdayEnd:'17:00'});
console.log(JSON.stringify({busy:days.map(day=>day.busy_minutes)}));
""")
assert result["busy"] == [0, 0, 0, 60, 0, 60, 0]
assert result["elapsed"] < 1000
def test_calendar_import_reuses_timezone_formatters_for_large_historical_calendars():
result = run_import("""
process.env.TZ='UTC';
const NativeDateTimeFormat=Intl.DateTimeFormat;
let formatterConstructions=0;
Intl.DateTimeFormat=function(...args) {
formatterConstructions+=1;
return new NativeDateTimeFormat(...args);
};
Intl.DateTimeFormat.prototype=NativeDateTimeFormat.prototype;
const event=`BEGIN:VEVENT\r\nDTSTART;TZID=America/New_York:20000101T090000\r\nDTEND;TZID=America/New_York:20000101T100000\r\nRRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;INTERVAL=2\r\nEND:VEVENT\r\n`;
const source='BEGIN:VCALENDAR\\r\\nVERSION:2.0\\r\\n'+event.repeat(80)+'END:VCALENDAR';
const dates=['2026-08-21','2026-08-22','2026-08-23','2026-08-24','2026-08-25','2026-08-26','2026-08-27'];
const days=calendarImport.review(source,{dates,workdayStart:'09:00',workdayEnd:'17:00'});
console.log(JSON.stringify({formatterConstructions,busy:days.map(day=>day.busy_minutes)}));
""")
assert result["busy"] == [0, 0, 0, 60, 0, 60, 0]
assert result["formatterConstructions"] <= 3
def test_calendar_import_expands_bounded_daily_recurrence_and_honors_exdate():