Skip to content

Instantly share code, notes, and snippets.

@jimdiroffii
Created April 18, 2025 01:57
Show Gist options
  • Save jimdiroffii/d48ced249ab7dbcf7e4a06ed0459d370 to your computer and use it in GitHub Desktop.
Save jimdiroffii/d48ced249ab7dbcf7e4a06ed0459d370 to your computer and use it in GitHub Desktop.
A Stellarium script for finding the best date and time for viewing Mercury. The script tries to find when Mercury will be at least 5 degrees above the horizon, at least 0.0 magnitude, and within an hour of sunset or sunrise. The script is centered on Miami, Florida, and set to check for specific dates. Most variables need adjustment to work.
//////////////////////////////////////////////////////////////////////////////
// Stellarium Script: Mercury Twilight Search
// Date Range: Feb 10, 2025 – Apr 30, 2025
// Time Step: 5 minutes
// Location: Miami (lat: 25.7617, lon: -80.1918), ignoring DST complexities.
//////////////////////////////////////////////////////////////////////////////
// ------------------------ USER CONFIGURATION ------------------------
// Observing location
var observerLatitude = 25.7617;
var observerLongitude = -80.1918;
var observerAltitude = 2; // meters
var timezoneOffset = -5; // ignoring DST, just use EST offset
// Date range (UTC) – note that JS Date months are zero-based
var startDateUTC = new Date(Date.UTC(2025, 1, 10, 0, 0, 0)); // 2025-02-10 00:00:00 UTC
var endDateUTC = new Date(Date.UTC(2025, 3, 30, 23, 59, 59)); // 2025-04-30 23:59:59 UTC
// Mercury visibility constraints
var minAltitudeDeg = 5.0; // Must be above 5°
var maxMagnitude = 0.0; // Must be magnitude 0.0 or brighter
// Time step in minutes (5 minutes)
var timeStepMin = 5;
// Sunrise/sunset times (LOCAL) on start/end dates
// (Ignoring DST shift, we do a linear interpolation.)
var sunriseFeb10 = 6.9833; // ~6:59 local
var sunsetFeb10 = 18.1833; // ~18:11 local
var sunriseApr30 = 6.75; // ~6:45 local
var sunsetApr30 = 19.8667; // ~19:52 local
// We define a 1-hour margin before/after sunrise or sunset
var marginHours = 1;
// ------------------------ END CONFIGURATION --------------------------
// Set observer location in Stellarium
core.setObserverLocation(
observerLatitude,
observerLongitude,
observerAltitude,
timezoneOffset,
"Miami"
);
// Calculate total number of days in our search period
var totalDays = (endDateUTC - startDateUTC) / (24 * 3600 * 1000); // days as float
/**
* Linear interpolation helper:
* Given x in [0,1], returns startVal + x*(endVal - startVal).
*/
function lerp(startVal, endVal, x) {
return startVal + x * (endVal - startVal);
}
/**
* Returns an approximate local sunrise time (decimal hours)
* for a given fraction of the way between Feb 10 and Apr 30.
*/
function approximateSunrise(dayIndex) {
var fraction = dayIndex / totalDays; // from 0.0 (Feb10) to 1.0 (Apr30)
return lerp(sunriseFeb10, sunriseApr30, fraction);
}
/**
* Returns an approximate local sunset time (decimal hours)
* for a given fraction of the way between Feb 10 and Apr 30.
*/
function approximateSunset(dayIndex) {
var fraction = dayIndex / totalDays;
return lerp(sunsetFeb10, sunsetApr30, fraction);
}
/**
* Convert a local decimal hour (e.g., 6.9833) to a JS Date *in UTC*,
* for a particular UTC date.
*
* NOTE: Because we are ignoring DST, we assume a constant offset = timezoneOffset.
*/
function localHourToUTCDate(baseDateUTC, localDecHour) {
// localDecHour is something like 6.9833 (i.e. 6:59 local).
// Our offset is negative, e.g. -5 for EST. So local time = UTC + offset.
// => UTC hour = localHour + (-offset).
// Because offset is -5, local = UTC - 5 => UTC = local + 5.
var utcHour = localDecHour + (timezoneOffset * -1);
// Break down decimal hour
var hour = Math.floor(utcHour);
var minute = Math.floor((utcHour - hour) * 60);
var second = 0;
// Create a new date from baseDateUTC (copy the day/month/year),
// then set the hours/min/seconds to the calculated UTC time.
var newDate = new Date(baseDateUTC.getTime()); // clone
newDate.setUTCHours(hour, minute, second, 0);
return newDate;
}
/**
* Convert JS Date to Stellarium date string: "YYYY:MM:DDThh:mm:ss"
*/
function dateToStellariumDateString(jsDate) {
var year = jsDate.getUTCFullYear();
var month = jsDate.getUTCMonth() + 1; // 0-based => 1-based
var day = jsDate.getUTCDate();
var hour = jsDate.getUTCHours();
var min = jsDate.getUTCMinutes();
var sec = jsDate.getUTCSeconds();
function pad(num) { return (num < 10) ? "0"+num : ""+num; }
return year + ":" + pad(month) + ":" + pad(day) + "T" +
pad(hour) + ":" + pad(min) + ":" + pad(sec);
}
/**
* Check Mercury's altitude/magnitude at the given JS Date (UTC).
* Print if it meets our thresholds.
*/
function checkMercuryVisibility(jsDate) {
// Set Stellarium time
var stelDateStr = dateToStellariumDateString(jsDate);
core.setDate(stelDateStr, true);
var mercury = SolarSystem.getPlanet("Mercury");
if (!mercury) {
print("Error: Could not retrieve Mercury object!");
return;
}
// Altitude in radians => convert to degrees
var altDeg = mercury.getAlt() * (180 / Math.PI);
var mag = mercury.getVMagnitude();
// Check thresholds
if (altDeg >= minAltitudeDeg && mag <= maxMagnitude) {
print("UTC=" + jsDate.toISOString() +
" | Alt=" + altDeg.toFixed(2) +
"° | Mag=" + mag.toFixed(2));
}
}
// -------------------- MAIN LOOP --------------------
print("Starting Mercury Twilight Search...");
// Current date pointer (UTC)
var currentDate = new Date(startDateUTC.getTime());
// We'll iterate day by day
while (currentDate <= endDateUTC) {
// dayIndex = how far we are between start & end
var dayIndex = (currentDate - startDateUTC) / (24 * 3600 * 1000);
// Approx. local sunrise/sunset for this day
var srLocal = approximateSunrise(dayIndex);
var ssLocal = approximateSunset(dayIndex);
// Define the search intervals in local time:
// from (sunrise - margin) to (sunrise + margin), and similarly for sunset
var srStart = srLocal - marginHours; // e.g., 1 hr before sunrise
var srEnd = srLocal + marginHours; // 1 hr after
var ssStart = ssLocal - marginHours; // 1 hr before sunset
var ssEnd = ssLocal + marginHours; // 1 hr after
// We'll do a 5-minute step (in decimal hours, that is 5/60 = 0.0833)
var timeStepHrs = timeStepMin / 60.0;
// ---- Morning loop ----
var tLocal = srStart;
while (tLocal <= srEnd) {
var checkDateUTC = localHourToUTCDate(currentDate, tLocal);
checkMercuryVisibility(checkDateUTC);
tLocal += timeStepHrs;
}
// ---- Evening loop ----
tLocal = ssStart;
while (tLocal <= ssEnd) {
var checkDateUTC = localHourToUTCDate(currentDate, tLocal);
checkMercuryVisibility(checkDateUTC);
tLocal += timeStepHrs;
}
// Move to the next (UTC) day
currentDate.setUTCDate(currentDate.getUTCDate() + 1);
}
print("Search Completed.");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment