// ========================================== // 3. IDENTIFY STATUS (Live vs Reached vs Cancelled vs Diverted vs Not Started) // ========================================== $isReached = (isset($data['status_code']) && $data['status_code'] == 'reached') || (isset($data['isArrDSTN']) && $data['isArrDSTN'] == true); $isCancelled = !$isReached && (!empty($data['ISCANCEL']) && (int)$data['ISCANCEL'] === 1); // $isDiverted can be true even when $isReached is true (diverted train that arrived at new terminus) $isDiverted = !$isCancelled && (!empty($data['ISDIVERT']) && (int)$data['ISDIVERT'] === 1); // Diverted trains: API never sets status_code='reached'. Detect completion via last-station arrival flag or stale journey (>30h old). if (!$isReached && $isDiverted) { if (!empty($data['STNS'])) { $lastStn = end($data['STNS']); if (!empty($lastStn['ISA'])) $isReached = true; } if (!$isReached) { $_journeyDt = DateTime::createFromFormat('d-m-Y', $apiDate); if ($_journeyDt && (time() - $_journeyDt->getTimestamp()) > 30 * 3600) $isReached = true; } } $isNotStarted = !$isReached && !$isCancelled && !$isDiverted && ((isset($data['status_code']) && $data['status_code'] == 'not_started') || (isset($data['TRUNST']) && (int)$data['TRUNST'] === 0)); // ========================================== // 4. HELPER FUNCTIONS // ========================================== // Converts minutes to readable text function formatMinsToDelay($mins) { $m = (int)$mins; if ($m <= 0) return "RT"; $h = floor($m / 60); $rem = $m % 60; $res = []; if ($h > 0) $res[] = $h . ($h > 1 ? " hrs" : " hr"); if ($rem > 0) $res[] = $rem . " mins"; return implode(" ", $res); } // Handles string delays like "02:11" function formatDelayStr($timeStr) { if (empty($timeStr) || strtolower($timeStr) == "on time") return "RT"; $parts = explode(':', $timeStr); if (count($parts) == 2) { return formatMinsToDelay(((int)$parts[0] * 60) + (int)$parts[1]); } return $timeStr; } // Handles both H:i (Live) and H:i:s (History) -> AM/PM function formatTimeAMPM($timeStr) { if (empty($timeStr) || strtolower($timeStr) == 'source' || strtolower($timeStr) == 'destination' || $timeStr == '00:00:00' || $timeStr == '--') return '--'; $timeObj = DateTime::createFromFormat('H:i:s', $timeStr); if (!$timeObj && preg_match('/([0-9]{2}):([0-9]{2})/', $timeStr, $m)) { $timeObj = DateTime::createFromFormat('H:i', $m[1].':'.$m[2]); } if ($timeObj) { $formatted = $timeObj->format('h:i A'); return preg_replace('/[0-9]{2}:[0-9]{2}(:[0-9]{2})?/', $formatted, $timeStr, 1); } return $timeStr; } // Intelligent Unix Timestamp Tracker for Speed Math function getUnixSequential($timeStr, &$lastTimeRaw, &$globalDayOffset) { if (empty($timeStr) || strtolower($timeStr) == 'source' || strtolower($timeStr) == 'destination' || $timeStr == '--' || $timeStr == '00:00:00') return null; preg_match('/(\d{1,2}:\d{2})(:\d{2})?/', $timeStr, $m); if (!$m) return null; $t = strtotime($m[1]); if ($lastTimeRaw !== -1 && $t < ($lastTimeRaw - 21600)) { $globalDayOffset += 86400; } $lastTimeRaw = $t; return $t + $globalDayOffset; } // ========================================== // 5. EXTRACT SAFE VARIABLES // ========================================== $trainName = isset($data['train_name']) ? $data['train_name'] : (isset($data['trainName']) ? $data['trainName'] : 'N/A'); $stoppages = $data['STNS']; $sourceName = isset($data['SRCN']) ? $data['SRCN'] : $stoppages[0]['SN']; $destName = isset($data['DSTNN']) ? $data['DSTNN'] : end($stoppages)['SN']; $journeyDate = isset($data['STD']) ? $data['STD'] : $apiDate; $alertMsg = isset($data['AlertMsg']) ? $data['AlertMsg'] : ''; $totalDistance = isset($data['TTLDIST']) ? floatval($data['TTLDIST']) : floatval(end($stoppages)['DIST']); // Distance Covered Logic $coveredDistance = 0; $lastActiveIndex = -1; foreach ($stoppages as $i => $s) { if (isset($s['ISD']) && ($s['ISD'] || $s['ISA'])) { $lastActiveIndex = $i; $coveredDistance = isset($s['DIST']) ? floatval($s['DIST']) : $coveredDistance; } } $progressPercent = ($totalDistance > 0) ? min(100, round(($coveredDistance / $totalDistance) * 100)) : 0; // Extract diversion info whenever ISDIVERT=1 (runs even if train is also reached) $divertFrom = ''; $divertTo = ''; $divertMsg = ''; if ($isDiverted) { $excpRaw = isset($data['EXCP']) ? str_replace(['[', ']'], ['', ' |'], $data['EXCP']) : ''; $excpRaw = trim(rtrim(trim($excpRaw), '|')); $divertMsg = !empty($excpRaw) ? $excpRaw : trim($data['AlertMsg'] ?? ''); $divertFrom = isset($data['DFROM']) ? trim($data['DFROM']) : ''; $divertTo = isset($data['DTO']) ? trim($data['DTO']) : ''; } if ($isReached) { $lastUpdateText = !empty($data['CPOS']) ? $data['CPOS'] : (!empty($data['LUPDFULL']) ? $data['LUPDFULL'] : "Journey Completed"); $finalLateMins = isset($data['totalLateMins']) ? (int)$data['totalLateMins'] : (isset($data['LDEL']) ? (int)$data['LDEL'] : 0); $delayFormatted = formatMinsToDelay($finalLateMins); $statusColor = ($finalLateMins > 0) ? "danger" : "success"; } elseif ($isCancelled) { $cancelMsg = trim($data['CPOS'] ?? ($data['EXCP'] ? trim($data['EXCP'], '[]') : '')); $lastUpdateText = $cancelMsg ?: 'This train has been cancelled'; $delayFormatted = 'Cancelled'; $statusColor = 'danger'; } elseif ($isDiverted) { $lastUpdateText = $divertMsg ?: 'This train has been diverted from its original route'; $delayMins = isset($data['LDEL']) ? (int)$data['LDEL'] : 0; $delayFormatted = formatMinsToDelay($delayMins); $statusColor = ($delayMins > 0) ? "danger" : "success"; } elseif ($isNotStarted) { $schDep0 = isset($stoppages[0]['STD']) ? $stoppages[0]['STD'] : ''; $lastUpdateText = $schDep0 ? "Scheduled to depart at " . $schDep0 : (isset($data['LUPDFULL']) ? $data['LUPDFULL'] : "Yet to start from source"); $delayFormatted = 'Scheduled'; $statusColor = 'secondary'; } else { $lastUpdateText = isset($data['LUPDFULL']) ? $data['LUPDFULL'] : "Live Status Available"; $delayMins = isset($data['LDEL']) ? (int)$data['LDEL'] : 0; $delayFormatted = formatMinsToDelay($delayMins); $statusColor = ($delayMins > 0) ? "danger" : "success"; } $coachString = isset($data['STNS'][0]['departureCoachPosition']) ? $data['STNS'][0]['departureCoachPosition'] : ''; $coaches = $coachString ? explode('-', $coachString) : []; // Date navigation — Yesterday / Today / Tomorrow $_dateObj = DateTime::createFromFormat('d-m-Y', $apiDate) ?: new DateTime(); $_dateYest = (clone $_dateObj)->modify('-1 day')->format('Ymd'); $_dateCurr = $_dateObj->format('Ymd'); $_dateTomo = (clone $_dateObj)->modify('+1 day')->format('Ymd'); $_todayYmd = date('Ymd'); $_dateLabel = ($_dateCurr === $_todayYmd) ? 'Today' : $_dateObj->format('d M Y'); // Big delay — current delay in minutes $_currentDelayMins = 0; if (!$isReached && !$isCancelled && !$isNotStarted) { $_currentDelayMins = isset($data['LDEL']) ? (int)$data['LDEL'] : 0; } elseif ($isReached) { $_currentDelayMins = isset($data['totalLateMins']) ? (int)$data['totalLateMins'] : (isset($data['LDEL']) ? (int)$data['LDEL'] : 0); } // WhatsApp share URL $_shareUrl = 'https://runningstatus.in/status/' . urlencode($trainNo) . '-on-' . $_dateCurr; $_shareText = $trainName . ' (' . $trainNo . ') - ' . $delayFormatted . ' - ' . $_dateLabel . ' | ' . $_shareUrl; $_waUrl = 'https://wa.me/?text=' . rawurlencode($_shareText); ?>

12378 -

Running
Refreshing in 180s
Late
Source
Date
Destination
0 km 0 / 0 km · % 0 km