all repos — bibel @ e61fc65a61631125f782ff5d302389fe7c4a9228

Unnamed repository; edit this file 'description' to name the repository.

internal/easterprogression.go (view raw)

  1package bible
  2
  3import (
  4	"fmt"
  5	"time"
  6
  7	"maxwelljensen/bibel/pkg"
  8)
  9
 10// EasterProgression handles calculating time until Easter
 11type EasterProgression struct {
 12	easterType string // "orthodox" or "latin"
 13}
 14
 15// NewEasterProgression creates a new Easter progression calculator
 16func NewEasterProgression(easterType string) *EasterProgression {
 17	if easterType != "latin" && easterType != "orthodox" {
 18		easterType = "orthodox" // Default to orthodox
 19	}
 20	return &EasterProgression{easterType: easterType}
 21}
 22
 23// GetNextEasterDate calculates the date of the next Easter (Orthodox or Catholic)
 24func (ep *EasterProgression) GetNextEasterDate() (time.Time, error) {
 25	currentYear := time.Now().Year()
 26
 27	// Try current year
 28	var easterDate time.Time
 29	var err error
 30
 31	if ep.easterType == "latin" {
 32		easterDate, err = eastertime.CatholicByYear(currentYear)
 33	} else {
 34		easterDate, err = eastertime.OrthodoxByYear(currentYear)
 35	}
 36
 37	if err != nil {
 38		return time.Time{}, err
 39	}
 40
 41	now := time.Now()
 42
 43	// If Easter has already passed this year, try next year
 44	if easterDate.Before(now) {
 45		if ep.easterType == "latin" {
 46			easterDate, err = eastertime.CatholicByYear(currentYear + 1)
 47		} else {
 48			easterDate, err = eastertime.OrthodoxByYear(currentYear + 1)
 49		}
 50
 51		if err != nil {
 52			return time.Time{}, err
 53		}
 54	}
 55
 56	return easterDate, nil
 57}
 58
 59// GetTimeUntilEaster calculates the duration until the next Easter
 60func (ep *EasterProgression) GetTimeUntilEaster() (time.Duration, error) {
 61	easterDate, err := ep.GetNextEasterDate()
 62	if err != nil {
 63		return 0, err
 64	}
 65
 66	return time.Until(easterDate), nil
 67}
 68
 69// FormatEasterProgress formats the time until Easter as a human-readable string
 70func (ep *EasterProgression) FormatEasterProgress() (string, error) {
 71	duration, err := ep.GetTimeUntilEaster()
 72	if err != nil {
 73		return "", err
 74	}
 75
 76	// Calculate days, hours, minutes
 77	totalSeconds := int(duration.Seconds())
 78	days := totalSeconds / (24 * 60 * 60)
 79	remainingSeconds := totalSeconds % (24 * 60 * 60)
 80	hours := remainingSeconds / (60 * 60)
 81	remainingSeconds %= (60 * 60)
 82	minutes := remainingSeconds / 60
 83
 84	var label string
 85	if ep.easterType == "latin" {
 86		label = "Roman Catholic Easter"
 87	} else {
 88		label = "Easter"
 89	}
 90
 91	if days > 0 {
 92		return fmt.Sprintf("%s in %d days, %d hours, %d minutes", label, days, hours, minutes), nil
 93	} else if hours > 0 {
 94		return fmt.Sprintf("%s in %d hours, %d minutes", label, hours, minutes), nil
 95	} else {
 96		return fmt.Sprintf("%s in %d minutes", label, minutes), nil
 97	}
 98}
 99
100// GetEasterProgressPercentage returns progress as a percentage (0.0 to 1.0)
101// Since Easter is an annual event, we calculate progress through the year
102func (ep *EasterProgression) GetEasterProgressPercentage() (float64, error) {
103	currentYear := time.Now().Year()
104
105	// Get Easter date for current year
106	var currentEaster time.Time
107	var err error
108
109	if ep.easterType == "latin" {
110		currentEaster, err = eastertime.CatholicByYear(currentYear)
111	} else {
112		currentEaster, err = eastertime.OrthodoxByYear(currentYear)
113	}
114
115	if err != nil {
116		return 0.0, err
117	}
118
119	// Get Easter date for previous year to calculate yearly cycle
120	var previousEaster time.Time
121	if ep.easterType == "latin" {
122		previousEaster, err = eastertime.CatholicByYear(currentYear - 1)
123	} else {
124		previousEaster, err = eastertime.OrthodoxByYear(currentYear - 1)
125	}
126
127	if err != nil {
128		return 0.0, err
129	}
130
131	now := time.Now()
132
133	// If current Easter has passed, we're between current Easter and next Easter
134	if currentEaster.Before(now) {
135		// Get next Easter
136		var nextEaster time.Time
137		if ep.easterType == "latin" {
138			nextEaster, err = eastertime.CatholicByYear(currentYear + 1)
139		} else {
140			nextEaster, err = eastertime.OrthodoxByYear(currentYear + 1)
141		}
142
143		if err != nil {
144			return 0.0, err
145		}
146
147		// Progress from current Easter to next Easter
148		totalDuration := nextEaster.Sub(currentEaster)
149		elapsedDuration := now.Sub(currentEaster)
150
151		return elapsedDuration.Seconds() / totalDuration.Seconds(), nil
152	} else {
153		// We're between previous Easter and current Easter
154		totalDuration := currentEaster.Sub(previousEaster)
155		elapsedDuration := now.Sub(previousEaster)
156
157		return elapsedDuration.Seconds() / totalDuration.Seconds(), nil
158	}
159}
160