ashikahmad
2/4/2019 - 4:21 PM

Simple MoonPhase calculation in swift

import Foundation

enum MoonPhase: Int {
    case newMoon
    case waxingCrescent
    case firstQuarter
    case waxingGibbous
    case fullMoon
    case waningGibbous
    case lastQuarter
    case waningCrescent

    static let phaseMojis = ["🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"]
    static let phaseNames = ["New Moon", "Waxing Crescent", "First Quarter", "Waxing Gibbous",
                             "Full Moon", "Waning Moon", "Last Quarter", "Waning Crescent"]

    var emoji: String {
        return MoonPhase.phaseMojis[rawValue]
    }

    var name: String {
        return MoonPhase.phaseNames[rawValue]
    }

    init(day: Int, month: Int, year: Int) {
        var _month: Double = Double(month)
        var _year: Double = Double(year)
        let _day: Double = Double(day)

        if (_month < 3) {
            _year -= 1
            _month += 12
        }

        _month += 1
        let c = 365.25 * _year
        let e = 30.6 * _month
        var jd = c + e + _day - 694039.09 // jd is total days elapsed
        jd /= 29.5305882 // divide by the moon cycle
        var b = floor(jd) // int(jd) -> b, take integer part of jd
        jd -= b // subtract integer part to leave fractional part of original jd
        b = (jd * 8).rounded() // scale fraction from 0-8 and round

        if b >= 8 { b = 0 } // 0 and 8 are the same so turn 8 into 0
        self.init(rawValue: Int(b))!
    }

    init(for date: Date = Date()) {
        let calendar = Calendar(identifier: .gregorian)
        let day = calendar.component(.day, from: date)
        let month = calendar.component(.month, from: date)
        let year = calendar.component(.year, from: date)
        self.init(day: day, month: month, year: year)
    }
}

extension Date {
    static var current: Date { return Date() }
}

let phase = MoonPhase(day: 17, month: 2, year: 2019)
phase.emoji
phase.name

for d in 1...28 {
    let phase = MoonPhase(day: d, month: 2, year: 2019)
    print(phase.emoji, phase.name, "-", d)
}