Skip to content

Instantly share code, notes, and snippets.

@Shaddix
Created October 3, 2018 03:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Shaddix/30d7c6b7d6b3ad445ae62529fa56b387 to your computer and use it in GitHub Desktop.
Save Shaddix/30d7c6b7d6b3ad445ae62529fa56b387 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Threading;
namespace WebAppTests.DateTimeSpike
{
public class DateTimeProvider
{
private static readonly Lazy<DateTimeProvider> _lazyInstance = new Lazy<DateTimeProvider>(() => new DateTimeProvider());
public static DateTimeProvider Instance => _lazyInstance.Value;
private readonly Func<DateTimeOffset> _defaultDateTimeFunction = () => DateTimeOffset.Now;
private DateTimeProvider()
{
}
/// <summary>
/// DateTimeProvider.Instance.Now will return passed dateTime until return DateTimeProviderContext is disposed.
/// Use wrapped in using like:
/// using (var dateTimeContext = DateTimeProvider.Instance.SimulateTime(/*new DateTimeOffset()*/))
/// {
/// //DateTimeProvider.Instance.Now will return configured DateTime
/// }
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
internal DateTimeProviderContext SimulateTime(DateTimeOffset dateTime)
{
return new DateTimeProviderContext(dateTime);
}
public DateTimeOffset Now
{
get
{
if (DateTimeProviderContext.Current == null)
{
return _defaultDateTimeFunction.Invoke();
}
else
{
return DateTimeProviderContext.Current.ContextDateTimeNow;
}
}
}
}
internal class DateTimeProviderContext : IDisposable
{
private static readonly AsyncLocal<Stack<DateTimeProviderContext>> ScopeStack = new AsyncLocal<Stack<DateTimeProviderContext>>()
{
Value = new Stack<DateTimeProviderContext>()
};
public DateTimeOffset ContextDateTimeNow { get; set; }
public DateTimeProviderContext(DateTimeOffset contextDateTimeNow)
{
ContextDateTimeNow = contextDateTimeNow;
ScopeStack.Value.Push(this);
}
public static DateTimeProviderContext Current
{
get
{
if (ScopeStack.Value.Count == 0)
{
return null;
}
return ScopeStack.Value.Peek();
}
}
public static void Reset()
{
ScopeStack.Value.Clear();
}
public void Dispose()
{
try
{
ScopeStack.Value.Pop();
}
catch (Exception e)
{
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment