perf: reuse calendar timezone formatters (Closes #1285)
This commit is contained in:
parent
6eb2709477
commit
d8476c6f7b
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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():
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user