Task: Holidays related to Easter



C#: using System;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;

internal class Program
{
    private static readonly OrderedDictionary _holidayOffsets = new OrderedDictionary
                                                                    {
                                                                        {"Easter", 0},
                                                                        {"Ascension", 39},
                                                                        {"Pentecost", 49},
                                                                        {"Trinity", 56},
                                                                        {"Corpus", 60},
                                                                    };

    static void Main(string[] args)
    {
        Console.WriteLine("Christian holidays, related to Easter, for each centennial from 400 to 2100 CE:");
        for (int year = 400; year <= 2100; year += 100)
            OutputHolidays(year);

        Console.WriteLine();
        Console.WriteLine("Christian holidays, related to Easter, for years from 2010 to 2020 CE:");
        for (int year = 2010; year <= 2020; year += 1)
            OutputHolidays(year);
    }

    static void OutputHolidays(int year)
    {
        var easter = CalculateEaster(year);
        var holidays = from kp in _holidayOffsets.OfType<DictionaryEntry>()
                       let holiday = easter.AddDays(Convert.ToInt32(kp.Value))
                       select kp.Key + ": " + string.Format("{0,2:ddd} {0,2:%d} {0:MMM}", holiday);
        Console.WriteLine("{0,4} {1}", year, string.Join(", ", holidays.ToArray()));
    }

    static DateTime CalculateEaster(int year)
    {
        var a = year % 19;
        var b = year / 100;
        var c = year %100;
        var d = b / 4;
        var e = b % 4;
        var f = (b + 8) / 25;
        var g = (b - f + 1) / 3;
        var h = (19 * a + b - d - g + 15) % 30;
        var i = c / 4;
        var k = c % 4;
        var l = (32 + 2 * e + 2 * i - h - k) % 7;
        var m = (a + 11 * h + 22 * l) / 451;
        var numerator = h + l - 7 * m + 114;
        var month = numerator / 31;
        var day = (numerator % 31) + 1;
        return new DateTime(year, month, day);
    }
}


Go: package main

import (
    "fmt"
    "time"
)

type holiday struct {
    time.Time
}

func easter(y int) holiday {
    c := y / 100
    n := mod(y, 19)
    i := mod(c-c/4-(c-(c-17)/25)/3+19*n+15, 30)
    i -= (i / 28) * (1 - (i/28)*(29/(i+1))*((21-n)/11))
    l := i - mod(y+y/4+i+2-c+c/4, 7)
    m := 3 + (l+40)/44
    d := l + 28 - 31*(m/4)
    return holiday{time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.UTC)}
}

func mod(a, n int) int {
    r := a % n
    if r < 0 {
        return r + n
    }
    return r
}

func (h holiday) addDays(d int) holiday {
    return holiday{h.Add(time.Duration(d) * 24 * time.Hour)}
}

type easterRelated struct {
    easter, ascension, pentecost, trinity, corpusChristi holiday
}

func newEasterRelated(y int) (er easterRelated) {
    er.easter = easter(y)
    er.ascension = er.easter.addDays(39)
    er.pentecost = er.ascension.addDays(10)
    er.trinity = er.pentecost.addDays(7)
    er.corpusChristi = er.trinity.addDays(4)
    return
}

func (er easterRelated) print() {
    const wdmdm = ": Mon _2 Jan"
    fmt.Printf("%4d %s, %s, %s, %s, %s\n",
        er.easter.Year(),
        er.easter.Format("Easter"+wdmdm),
        er.ascension.Format("Ascension"+wdmdm),
        er.pentecost.Format("Pentecost"+wdmdm),
        er.trinity.Format("Trinity"+wdmdm),
        er.corpusChristi.Format("Corpus"+wdmdm))
}

func main() {
    fmt.Println("Christian holidays, related to Easter, " +
        "for each centennial from 400 to 2100 CE:")
    for y := 400; y <= 2100; y += 100 {
        newEasterRelated(y).print()
    }
    fmt.Println("\nChristian holidays, related to Easter, " +
        "for years from 2010 to 2020 CE:")
    for y := 2010; y <= 2020; y++ {
        newEasterRelated(y).print()
    }
}