Just a simple example initialized with the gsm.utils::MakeExample function.
# Compute lunar phase offline (no external APIs)
moon_phase <- function(date = Sys.Date()) {
year <- as.integer(format(date, "%Y"))
month <- as.integer(format(date, "%m"))
day <- as.integer(format(date, "%d"))
if (month < 3) {
year <- year - 1L
month <- month + 12L
}
month <- month + 1L
c_val <- 365.25 * year
e_val <- 30.6 * month
jd <- c_val + e_val + day - 694039.09
jd <- jd / 29.5305882
phase <- jd - floor(jd)
age <- phase * 29.5305882
phase_name <- if (age < 1.84566) {
"New Moon"
} else if (age < 5.53699) {
"Waxing Crescent"
} else if (age < 9.22831) {
"First Quarter"
} else if (age < 12.91963) {
"Waxing Gibbous"
} else if (age < 16.61096) {
"Full Moon"
} else if (age < 20.30228) {
"Waning Gibbous"
} else if (age < 23.99361) {
"Last Quarter"
} else if (age < 27.68493) {
"Waning Crescent"
} else {
"New Moon"
}
emoji <- switch(
phase_name,
"New Moon" = "🌑",
"Waxing Crescent" = "🌒",
"First Quarter" = "🌓",
"Waxing Gibbous" = "🌔",
"Full Moon" = "🌕",
"Waning Gibbous" = "🌖",
"Last Quarter" = "🌗",
"Waning Crescent" = "🌘",
"🌑"
)
list(age_days = age, phase = phase_name, emoji = emoji)
}
moon_info <- moon_phase(Sys.Date())
message(
"Goodnight, moon! In Durham, NC (offline estimate), today is a ",
moon_info$phase,
" ",
moon_info$emoji,
" (lunar age ~ ",
sprintf("%.1f", moon_info$age_days),
" days). Rendered on ",
Sys.time()
)
## Goodnight, moon! In Durham, NC (offline estimate), today is a Waxing Gibbous 🌔 (lunar age ~ 12.4 days). Rendered on 2026-01-30 20:13:32.050321