all repos — bibel @ c045b445fe953f81a929780728841400a44ce422

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	switch {
 92	case days > 0:
 93		return fmt.Sprintf("%s in %d days, %d hours, %d minutes", label, days, hours, minutes), nil
 94	case hours > 0:
 95		return fmt.Sprintf("%s in %d hours, %d minutes", label, hours, minutes), nil
 96	default:
 97		return fmt.Sprintf("%s in %d minutes", label, minutes), nil
 98	}
 99}
100
101// GetEasterProgressPercentage returns progress as a percentage (0.0 to 1.0)
102// Since Easter is an annual event, we calculate progress through the year
103func (ep *EasterProgression) GetEasterProgressPercentage() (float64, error) {
104	currentYear := time.Now().Year()
105
106	// Get Easter date for current year
107	var currentEaster time.Time
108	var err error
109
110	if ep.easterType == "latin" {
111		currentEaster, err = eastertime.CatholicByYear(currentYear)
112	} else {
113		currentEaster, err = eastertime.OrthodoxByYear(currentYear)
114	}
115
116	if err != nil {
117		return 0.0, err
118	}
119
120	// Get Easter date for previous year to calculate yearly cycle
121	var previousEaster time.Time
122	if ep.easterType == "latin" {
123		previousEaster, err = eastertime.CatholicByYear(currentYear - 1)
124	} else {
125		previousEaster, err = eastertime.OrthodoxByYear(currentYear - 1)
126	}
127
128	if err != nil {
129		return 0.0, err
130	}
131
132	now := time.Now()
133
134	// If current Easter has passed, we're between current Easter and next Easter
135	if currentEaster.Before(now) {
136		// Get next Easter
137		var nextEaster time.Time
138		if ep.easterType == "latin" {
139			nextEaster, err = eastertime.CatholicByYear(currentYear + 1)
140		} else {
141			nextEaster, err = eastertime.OrthodoxByYear(currentYear + 1)
142		}
143
144		if err != nil {
145			return 0.0, err
146		}
147
148		// Progress from current Easter to next Easter
149		totalDuration := nextEaster.Sub(currentEaster)
150		elapsedDuration := now.Sub(currentEaster)
151
152		return elapsedDuration.Seconds() / totalDuration.Seconds(), nil
153	} else {
154		// We're between previous Easter and current Easter
155		totalDuration := currentEaster.Sub(previousEaster)
156		elapsedDuration := now.Sub(previousEaster)
157
158		return elapsedDuration.Seconds() / totalDuration.Seconds(), nil
159	}
160}
161