This commit is contained in:
Zachary
2024-11-10 19:53:59 +01:00
parent a5d4a66078
commit eb7ec1f8bd
2 changed files with 218 additions and 32 deletions

View File

@@ -68,7 +68,7 @@
background-color: #333;
}
.holiday {
background-color: #555;
background-color: #3b1e6e;
cursor: pointer;
}
.optimized {

View File

@@ -13,6 +13,7 @@
let holidays = [];
let daysOff = 24; // Default days off per year
let optimizedDaysOff = [];
let extendedHolidays = [];
function handleYearChange(event) {
year = parseInt(event.target.value);
@@ -40,9 +41,127 @@
}));
console.log('Holidays:', holidays);
optimizeDaysOff();
calculateExtendedHolidays();
}
}
function optimizeDaysOff() {
// Reset optimized days off
optimizedDaysOff = [];
// Combine holidays and weekends
const allDays = holidays.map(h => h.date);
let daysToUse = daysOff;
// Create a list of potential days to take off, sorted by their potential to extend holidays
const potentialDaysOff = [];
for (let month = 0; month < 12; month++) {
for (let day = 1; day <= 31; day++) {
const date = new Date(year, month, day);
if (date.getMonth() !== month) break; // Skip invalid dates
const isWeekend = date.getDay() === 0 || date.getDay() === 6;
const isHoliday = allDays.some(d => d.getTime() === date.getTime());
if (!isWeekend && !isHoliday) {
const prevDay = new Date(date);
prevDay.setDate(date.getDate() - 1);
const nextDay = new Date(date);
nextDay.setDate(date.getDate() + 1);
const extendsHoliday =
allDays.some(d => d.getTime() === prevDay.getTime()) ||
allDays.some(d => d.getTime() === nextDay.getTime());
if (extendsHoliday) {
potentialDaysOff.push(date);
}
}
}
}
// Sort potential days off by their ability to extend existing chains with multiple holidays
potentialDaysOff.sort((a, b) => {
const aConsecutive = calculateConsecutiveDaysIncludingHoliday(a, allDays);
const bConsecutive = calculateConsecutiveDaysIncludingHoliday(b, allDays);
return bConsecutive - aConsecutive || a.getTime() - b.getTime();
});
// Select days off from the sorted list, prioritizing those that extend chains with multiple holidays
for (let i = 0; i < potentialDaysOff.length && daysToUse > 0; i++) {
const date = potentialDaysOff[i];
const prevDay = new Date(date);
prevDay.setDate(date.getDate() - 1);
const nextDay = new Date(date);
nextDay.setDate(date.getDate() + 1);
// Check if adding this day creates a longer chain with multiple holidays
if (calculateConsecutiveDaysIncludingHoliday(date, allDays) > 0) {
optimizedDaysOff.push(date);
daysToUse--;
}
}
// Attempt to create full week chains
if (daysToUse > 0) {
for (let i = 0; i < optimizedDaysOff.length && daysToUse > 0; i++) {
const date = optimizedDaysOff[i];
const startOfWeek = new Date(date);
startOfWeek.setDate(date.getDate() - date.getDay() + 1); // Start of the week (Monday)
const endOfWeek = new Date(startOfWeek);
endOfWeek.setDate(startOfWeek.getDate() + 4); // End of the week (Friday)
for (let d = new Date(startOfWeek); d <= endOfWeek && daysToUse > 0; d.setDate(d.getDate() + 1)) {
if (!optimizedDaysOff.some(optDate => optDate.getTime() === d.getTime()) && !allDays.some(holiday => holiday.getTime() === d.getTime())) {
optimizedDaysOff.push(new Date(d));
daysToUse--;
}
}
}
}
console.log('Optimized Days Off:', optimizedDaysOff);
}
function calculateConsecutiveDaysIncludingHoliday(date, allDays) {
let consecutiveDays = 0;
let prevDay = new Date(date);
let nextDay = new Date(date);
let includesHoliday = false;
let holidayCount = 0;
// Count consecutive days before the date
while (true) {
prevDay.setDate(prevDay.getDate() - 1);
if (prevDay.getDay() === 0 || prevDay.getDay() === 6 || allDays.some(d => d.getTime() === prevDay.getTime())) {
consecutiveDays++;
if (allDays.some(d => d.getTime() === prevDay.getTime())) {
includesHoliday = true;
holidayCount++;
}
} else {
break;
}
}
// Count consecutive days after the date
while (true) {
nextDay.setDate(nextDay.getDate() + 1);
if (nextDay.getDay() === 0 || nextDay.getDay() === 6 || allDays.some(d => d.getTime() === nextDay.getTime())) {
consecutiveDays++;
if (allDays.some(d => d.getTime() === nextDay.getTime())) {
includesHoliday = true;
holidayCount++;
}
} else {
break;
}
}
return includesHoliday ? holidayCount : 0;
}
function formatDate(date) {
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
}
@@ -52,6 +171,7 @@
if (!isNaN(value)) {
daysOff = value;
optimizeDaysOff();
calculateExtendedHolidays();
} else {
event.target.textContent = daysOff; // Revert to previous valid value if input is invalid
}
@@ -62,41 +182,107 @@
event.target.textContent = value.replace(/\D/g, '');
}
function optimizeDaysOff() {
// Reset optimized days off
optimizedDaysOff = [];
function calculateExtendedHolidays() {
const allDays = holidays.map(h => h.date); // Include all holiday dates
let remainingDaysOff = daysOff; // Track remaining days off
// Combine holidays and weekends
const allDays = holidays.map(h => h.date);
let daysToUse = daysOff;
for (let month = 0; month < 12; month++) {
for (let day = 1; day <= 31; day++) {
const date = new Date(year, month, day);
if (date.getMonth() !== month) break; // Skip invalid dates
const isWeekend = date.getDay() === 0 || date.getDay() === 6;
const isHoliday = allDays.some(d => d.getTime() === date.getTime());
// Check if the day before or after a weekend/holiday can be used to extend it
if ((isWeekend || isHoliday) && daysToUse > 0) {
const prevDay = new Date(date);
prevDay.setDate(date.getDate() - 1);
const nextDay = new Date(date);
nextDay.setDate(date.getDate() + 1);
extendedHolidays = holidays
.filter(holiday => holiday.date.getDay() !== 0 && holiday.date.getDay() !== 6) // Only non-weekend holidays
.map(holiday => {
let startDate = new Date(holiday.date);
let endDate = new Date(holiday.date);
let daysUsed = 0;
// Extend before the holiday
while (daysUsed < remainingDaysOff) {
const prevDay = new Date(startDate);
prevDay.setDate(startDate.getDate() - 1);
if (!allDays.some(d => d.getTime() === prevDay.getTime()) && prevDay.getDay() !== 0 && prevDay.getDay() !== 6) {
optimizedDaysOff.push(new Date(prevDay));
daysToUse--;
} else if (!allDays.some(d => d.getTime() === nextDay.getTime()) && nextDay.getDay() !== 0 && nextDay.getDay() !== 6) {
optimizedDaysOff.push(new Date(nextDay));
daysToUse--;
startDate = prevDay;
daysUsed++;
} else {
break;
}
}
// Extend after the holiday
while (daysUsed < remainingDaysOff) {
const nextDay = new Date(endDate);
nextDay.setDate(endDate.getDate() + 1);
if (!allDays.some(d => d.getTime() === nextDay.getTime()) && nextDay.getDay() !== 0 && nextDay.getDay() !== 6) {
endDate = nextDay;
daysUsed++;
} else {
break;
}
}
remainingDaysOff -= daysUsed; // Deduct used days from remaining
// Calculate total consecutive days including weekends
const totalDays = calculateTotalConsecutiveDays(startDate, endDate, allDays);
return {
holidayName: holiday.name,
startDate: formatDate(startDate),
endDate: formatDate(endDate),
totalDays
};
});
// If there are remaining days off, try to use them to extend any holiday further
if (remainingDaysOff > 0) {
extendedHolidays.forEach(extended => {
let startDate = new Date(extended.startDate);
let endDate = new Date(extended.endDate);
// Extend before the holiday
while (remainingDaysOff > 0) {
const prevDay = new Date(startDate);
prevDay.setDate(startDate.getDate() - 1);
if (!allDays.some(d => d.getTime() === prevDay.getTime()) && prevDay.getDay() !== 0 && prevDay.getDay() !== 6) {
startDate = prevDay;
remainingDaysOff--;
} else {
break;
}
}
// Extend after the holiday
while (remainingDaysOff > 0) {
const nextDay = new Date(endDate);
nextDay.setDate(endDate.getDate() + 1);
if (!allDays.some(d => d.getTime() === nextDay.getTime()) && nextDay.getDay() !== 0 && nextDay.getDay() !== 6) {
endDate = nextDay;
remainingDaysOff--;
} else {
break;
}
}
extended.startDate = formatDate(startDate);
extended.endDate = formatDate(endDate);
extended.totalDays = calculateTotalConsecutiveDays(startDate, endDate, allDays);
});
}
}
function calculateTotalConsecutiveDays(startDate, endDate, allDays) {
let totalDays = 0;
let currentDate = new Date(startDate);
while (currentDate <= endDate) {
const isWeekend = currentDate.getDay() === 0 || currentDate.getDay() === 6;
const isHoliday = allDays.some(d => d.getTime() === currentDate.getTime());
if (isWeekend || isHoliday || optimizedDaysOff.some(d => d.getTime() === currentDate.getTime())) {
totalDays++;
}
currentDate.setDate(currentDate.getDate() + 1);
}
console.log('Optimized Days Off:', optimizedDaysOff);
return totalDays;
}
// Initialize holidays on load
@@ -201,11 +387,11 @@
</div>
<div>
There are {holidays.length} public holidays in {selectedCountry}:
Extended Holidays:
<ul>
{#each holidays as holiday}
<li class={optimizedDaysOff.some(d => d.getTime() === holiday.date.getTime()) ? 'highlight' : ''}>
{holiday.name} on {formatDate(holiday.date)}
{#each extendedHolidays as extended}
<li>
{extended.totalDays} day holiday, including {extended.holidayName} from {extended.startDate} to {extended.endDate}
</li>
{/each}
</ul>