wttr/src/Moon.zig

71 lines
2.1 KiB
Zig

const std = @import("std");
const c = @cImport({
@cInclude("time.h");
@cInclude("astro.h");
});
pub const Phase = struct {
phase: f64, // 0.0 to 1.0 (0=new, 0.25=first quarter, 0.5=full, 0.75=last quarter)
illuminated: f64, // 0.0 to 1.0
age_days: f64, // Age in days
distance_km: f64,
angular_diameter: f64,
pub fn emoji(self: Phase) []const u8 {
const p = self.phase;
if (p < 0.0625) return "🌑"; // New moon
if (p < 0.1875) return "🌒"; // Waxing crescent
if (p < 0.3125) return "🌓"; // First quarter
if (p < 0.4375) return "🌔"; // Waxing gibbous
if (p < 0.5625) return "🌕"; // Full moon
if (p < 0.6875) return "🌖"; // Waning gibbous
if (p < 0.8125) return "🌗"; // Last quarter
if (p < 0.9375) return "🌘"; // Waning crescent
return "🌑"; // New moon
}
pub fn day(self: Phase) u8 {
return @intFromFloat(@round(self.age_days));
}
};
pub fn getPhase(timestamp: i64) Phase {
const julian = c.unix_to_julian(@intCast(timestamp));
var illuminated: f64 = 0;
var age_days: f64 = 0;
var distance: f64 = 0;
var angular_diameter: f64 = 0;
var sun_distance: f64 = 0;
var sun_angular_diameter: f64 = 0;
const phase_angle = c.phase(
julian,
&illuminated,
&age_days,
&distance,
&angular_diameter,
&sun_distance,
&sun_angular_diameter,
);
return .{
.phase = phase_angle,
.illuminated = illuminated,
.age_days = age_days,
.distance_km = distance,
.angular_diameter = angular_diameter,
};
}
test "moon phase calculation" {
// Test a known date: 2024-01-01 00:00:00 UTC
const timestamp: i64 = 1704067200;
const moon = getPhase(timestamp);
try std.testing.expect(moon.phase >= 0.0 and moon.phase <= 1.0);
try std.testing.expect(moon.illuminated >= 0.0 and moon.illuminated <= 1.0);
try std.testing.expect(moon.age_days >= 0.0 and moon.age_days <= 29.53);
try std.testing.expect(moon.distance_km > 0);
}