odac.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IGS Orbit Data Availability Calculator</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            line-height: 1.6;
        }
        h1, h2, h3 {
            color: #333;
        }
        .calendar-container {
            margin: 20px 0;
        }
        .info-box {
            background-color: #f8f8f8;
            border: 1px solid #ddd;
            padding: 15px;
            margin-top: 15px;
            border-radius: 5px;
        }
        input[type="date"] {
            padding: 8px;
            font-size: 16px;
            margin-bottom: 15px;
        }
        /* Day grid styling */
        .day-grid {
            width: 100%;
            margin-top: 20px;
            margin-bottom: 20px;
            border-collapse: collapse;
        }
        .day-grid th {
            background-color: #f2f2f2;
            padding: 8px;
            text-align: center;
            border: 1px solid #ddd;
        }
        .day-grid td {
            padding: 8px;
            text-align: center;
            border: 1px solid #ddd;
            cursor: pointer;
        }
        .day-grid td:hover {
            background-color: #e6f7ff;
        }
        .day-grid .week-number {
            background-color: #f2f2f2;
            font-weight: bold;
        }
        .day-grid .current-day {
            background-color: #ffeb3b;
            font-weight: bold;
        }
        .day-grid .selected-day {
            background-color: #bbdefb;
            font-weight: bold;
        }
        .day-grid .empty-cell {
            background-color: #f9f9f9;
            cursor: default;
        }
    </style>
</head>
<body>
    <h1>IGS Orbit Data Availability Calculator</h1>
 
    <div class="calendar-container">
 
        <!-- Day Grid -->
        <table class="day-grid" id="day-grid">
            <!-- Will be populated by JavaScript -->
        </table>
 
        <!-- Date Picker -->
        <input type="date" id="date-picker">
 
        <div id="selected-date-info" class="info-box">
            <h2>Selected Date Information</h2>
            <p id="selected-date"></p>
            <p id="selected-gps-day"></p>
            <p id="selected-gps-week"></p>
            <h3>Approximate Orbit Data Availability for Selected Date</h3>
            <p id="selected-ultra-rapid"></p>
            <p id="selected-rapid"></p>
            <p id="selected-final"></p>
            <p style="font-size: 0.9em; margin-top: 20px; color: #555;">
                The ultra-rapid product, useful for real-time and near real-time applications, at regular intervals four times per day; the ultra-rapid solution includes both observed and predicted satellite orbits and clocks. The rapid orbit and clock combination is a daily solution available approximately 17 hours after the end of the previous UTC day. The final, and most consistent and highest quality IGS solutions, consists of daily orbit and clock files, generated on a weekly basis approximately 13 days after the end of the solution week.
                <br>Source: <a href="https://cddis.nasa.gov/Data_and_Derived_Products/GNSS/orbit_and_clock_products.html" target="_blank">https://cddis.nasa.gov/Data_and_Derived_Products/GNSS/orbit_and_clock_products.html</a>
            </p>
        </div>
    </div>
 
    <script>
        // Constants
        const MS_PER_DAY = 86400000; // 24 * 60 * 60 * 1000
        const GPS_EPOCH = new Date('January 6, 1980 00:00:00 UTC');
        const DAYS_OF_WEEK = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
 
        // Calculate GPS day of year
        function getDayOfYear(date) {
            const start = new Date(Date.UTC(date.getFullYear(), 0, 0));
            const diff = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - start;
            return Math.round(diff / MS_PER_DAY);
        }
 
        // Calculate GPS week
        function getGPSWeek(date) {
            const diffDays = Math.floor((date - GPS_EPOCH) / MS_PER_DAY);
            return Math.floor(diffDays / 7);
        }
 
        // Get day of GPS week (0 = Sunday, 6 = Saturday)
        function getDayOfGPSWeek(date) {
            const diffDays = Math.floor((date - GPS_EPOCH) / MS_PER_DAY);
            return diffDays % 7;
        }
 
        // Format date for display
        function formatDate(date) {
            return date.toLocaleString('en-US', { 
                weekday: 'long', 
                year: 'numeric', 
                month: 'long', 
                day: 'numeric'
            });
        }
 
        // Calculate when ultra-rapid data will be available
        function getUltraRapidAvailability(date) {
            const hours = date.getUTCHours();
            let nextSlot;
 
            // Ultra-rapid data is available 4 times per day (00:00, 06:00, 12:00, 18:00 UTC)
            if (hours < 6) {
                nextSlot = 6;
            } else if (hours < 12) {
                nextSlot = 12;
            } else if (hours < 18) {
                nextSlot = 18;
            } else {
                nextSlot = 24;
            }
 
            const availabilityDate = new Date(date);
            availabilityDate.setUTCHours(nextSlot, 0, 0, 0);
 
            return availabilityDate;
        }
 
        // Calculate when rapid data will be available
        function getRapidAvailability(date) {
            // Rapid orbit combination is available approximately 17 hours after the end of the previous UTC day
            const nextDay = new Date(date);
            nextDay.setUTCDate(nextDay.getUTCDate() + 1);
            nextDay.setUTCHours(0, 0, 0, 0);
 
            const availabilityDate = new Date(nextDay);
            availabilityDate.setUTCHours(17, 0, 0, 0);
 
            return availabilityDate;
        }
 
        // Calculate when final data will be available
        function getFinalAvailability(date) {
            // Final orbit combination is available approximately 13 days after the end of the solution week
            const dayOfWeek = date.getUTCDay(); // 0 = Sunday, 6 = Saturday
            const daysUntilSaturday = (6 - dayOfWeek) % 7;
 
            const endOfWeek = new Date(date);
            endOfWeek.setUTCDate(endOfWeek.getUTCDate() + daysUntilSaturday);
            endOfWeek.setUTCHours(23, 59, 59, 999);
 
            const availabilityDate = new Date(endOfWeek);
            availabilityDate.setUTCDate(availabilityDate.getUTCDate() + 13);
 
            return availabilityDate;
        }
 
        // Update info for selected date
        function updateSelectedDateInfo() {
            const dateStr = document.getElementById('date-picker').value;
            if (!dateStr) return;
 
            const selectedDate = new Date(dateStr);
            selectedDate.setUTCHours(12, 0, 0, 0); // Set to noon UTC for consistency
 
            document.getElementById('selected-date').textContent = `Selected Date: ${formatDate(selectedDate)}`;
            document.getElementById('selected-gps-day').textContent = `GPS Day of Year: ${getDayOfYear(selectedDate)}`;
            document.getElementById('selected-gps-week').textContent = `GPS Week: ${getGPSWeek(selectedDate)} (Day ${getDayOfGPSWeek(selectedDate)})`;
 
            const ultraRapidAvailability = getUltraRapidAvailability(selectedDate);
            const rapidAvailability = getRapidAvailability(selectedDate);
            const finalAvailability = getFinalAvailability(selectedDate);
 
            document.getElementById('selected-ultra-rapid').textContent = `Ultra-Rapid: Available at ${formatDate(ultraRapidAvailability)}`;
            document.getElementById('selected-rapid').textContent = `Rapid: Available at ${formatDate(rapidAvailability)}`;
            document.getElementById('selected-final').textContent = `Final: Available at ${formatDate(finalAvailability)}`;
 
            // Update the selected day in the grid
            updateSelectedDayInGrid(selectedDate);
        }
 
        // Update selected day highlight in the grid
        function updateSelectedDayInGrid(selectedDate) {
            // Remove previous selection
            const previousSelected = document.querySelector('.day-grid .selected-day');
            if (previousSelected) {
                previousSelected.classList.remove('selected-day');
            }
 
            // Get selected date in YYYY-MM-DD format
            const selectedDateStr = selectedDate.toISOString().split('T')[0];
 
            // Find and highlight the new selected date
            const cells = document.querySelectorAll('.day-grid td[data-date]');
            for (let cell of cells) {
                if (cell.getAttribute('data-date') === selectedDateStr) {
                    cell.classList.add('selected-day');
                    break;
                }
            }
        }
 
        // Generate and populate the day grid
        function generateDayGrid() {
            const today = new Date();
            today.setHours(0, 0, 0, 0);
 
            const dayGrid = document.getElementById('day-grid');
            dayGrid.innerHTML = '';
 
            // Create header row
            const headerRow = document.createElement('tr');
            headerRow.innerHTML = `
                <th>Week</th>
                <th>Sun</th>
                <th>Mon</th>
                <th>Tue</th>
                <th>Wed</th>
                <th>Thu</th>
                <th>Fri</th>
                <th>Sat</th>
            `;
            dayGrid.appendChild(headerRow);
 
            // Find the start of the current week (Sunday)
            const currentDayOfWeek = today.getDay();
            const startOfCurrentWeek = new Date(today);
            startOfCurrentWeek.setDate(today.getDate() - currentDayOfWeek);
 
            // Calculate the start date for the grid (3 weeks before current week)
            const startDate = new Date(startOfCurrentWeek);
            startDate.setDate(startDate.getDate() - (3 * 7));
 
            // Generate 6 rows (6 weeks)
            let currentDate = new Date(startDate);
 
            for (let week = 0; week < 6; week++) {
                const row = document.createElement('tr');
 
                // Add week number (GPS week)
                const weekCell = document.createElement('td');
                weekCell.textContent = getGPSWeek(currentDate);
                weekCell.className = 'week-number';
                row.appendChild(weekCell);
 
                // Add days of the week
                for (let day = 0; day < 7; day++) {
                    const dayCell = document.createElement('td');
                    const cellDate = new Date(currentDate);
 
                    // Format date for display in the cell
                    dayCell.innerHTML = `${cellDate.getDate()}<br><span style="font-size: 0.8em">(${getDayOfYear(cellDate)})</span>`;
 
                    // Store the full date as a data attribute
                    const dateStr = cellDate.toISOString().split('T')[0];
                    dayCell.setAttribute('data-date', dateStr);
 
                    // Highlight current day
                    if (cellDate.toDateString() === today.toDateString()) {
                        dayCell.classList.add('current-day');
                    }
 
                    // Add click event to select this date
                    dayCell.addEventListener('click', function() {
                        document.getElementById('date-picker').value = dateStr;
                        updateSelectedDateInfo();
                    });
 
                    row.appendChild(dayCell);
 
                    // Move to next day
                    currentDate.setDate(currentDate.getDate() + 1);
                }
 
                dayGrid.appendChild(row);
            }
        }
 
        // Initialize the page
        window.onload = function() {
            // Generate the day grid
            generateDayGrid();
 
            // Set date picker to today
            const today = new Date();
            const formattedDate = today.toISOString().split('T')[0];
            document.getElementById('date-picker').value = formattedDate;
 
            // Update selected date info (which is today by default)
            updateSelectedDateInfo();
 
            // Set up event listener for date picker
            document.getElementById('date-picker').addEventListener('change', updateSelectedDateInfo);
        };
    </script>
</body>
</html>