Skip to content

Commit

Permalink
Merge pull request #97 from SumanKNath/master
Browse files Browse the repository at this point in the history
Make EasterBasedHoliday threadsafe
  • Loading branch information
joaomatossilva authored Jan 16, 2020
2 parents afcc958 + e4e2398 commit c961774
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 19 deletions.
26 changes: 7 additions & 19 deletions src/DateTimeExtensions/WorkingDays/EasterBasedHoliday.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#endregion

using DateTimeExtensions.Common;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -28,25 +29,18 @@ namespace DateTimeExtensions.WorkingDays
public class EasterBasedHoliday : Holiday
{
private int daysOffset;
private IDictionary<int, DateTime> dayCache;
private readonly ConcurrentLazyDictionary<int, DateTime> dayCache;

public EasterBasedHoliday(string name, int daysOffset)
: base(name)
{
this.daysOffset = daysOffset;
dayCache = new Dictionary<int, DateTime>();
dayCache = new ConcurrentLazyDictionary<int, DateTime>();
}

public override DateTime? GetInstance(int year)
{
if (dayCache.ContainsKey(year))
{
return dayCache[year];
}
var easter = EasterCalculator.CalculateEasterDate(year);
var date = easter.AddDays(daysOffset);
dayCache.Add(year, date);
return date;
return dayCache.GetOrAdd(year, () => EasterCalculator.CalculateEasterDate(year).AddDays(daysOffset));
}

public override bool IsInstanceOf(DateTime date)
Expand All @@ -57,22 +51,16 @@ public override bool IsInstanceOf(DateTime date)

public static class EasterCalculator
{
private static IDictionary<int, DateTime> easterPerYear;
private static ConcurrentLazyDictionary<int, DateTime> easterPerYear;

static EasterCalculator()
{
easterPerYear = new Dictionary<int, DateTime>();
easterPerYear = new ConcurrentLazyDictionary<int, DateTime>();
}

public static DateTime CalculateEasterDate(int year)
{
if (easterPerYear.ContainsKey(year))
{
return easterPerYear[year];
}
var easter = GetEasterDate(year);
easterPerYear.Add(year, easter);
return easter;
return easterPerYear.GetOrAdd(year, () => GetEasterDate(year));
}

//Algoritm downloaded from http://tiagoe.blogspot.com/2007/10/easter-calculation-in-c.html
Expand Down
22 changes: 22 additions & 0 deletions tests/DateTimeExtensions.Tests/ThreadSafeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,27 @@ public void AddWorkingDays_MultipleThreads_CanCalculate()
//Act
Parallel.ForEach(Enumerable.Range(1,10), (i) => startDate.AddWorkingDays(i, culture));
}

[Test]
public void CheckEaster_MultipleThreads()
{
Parallel.ForEach(Enumerable.Range(1, 10), (i) => ascencion_is_39_days_after_easter());
}

private void ascencion_is_39_days_after_easter()
{
var year = 2025;
var easterDate = new DateTime(2025, 4, 20);

var ascencionHoliday = ChristianHolidays.Ascension;
var ascencion = ascencionHoliday.GetInstance(year);
Assert.IsTrue(ascencion.HasValue);
Assert.AreEqual(DayOfWeek.Thursday, ascencion.Value.DayOfWeek);

//source: http://en.wikipedia.org/wiki/Ascension_Day
// Ascension Day is traditionally celebrated on a Thursday, the fortieth day of Easter
// again, easter day is included
Assert.AreEqual(easterDate.AddDays(39), ascencion.Value);
}
}
}

0 comments on commit c961774

Please sign in to comment.