Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
mattiasnordqvist committed Jul 6, 2024
1 parent 9ec4883 commit 97406d5
Show file tree
Hide file tree
Showing 12 changed files with 170 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Version>1.0.0</Version>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace DotNetThoughts.TimeKeeping;
namespace DotNetThoughts.LocalTimeKit;

/// <summary>
/// Unambigious representation of a local datetime
Expand All @@ -13,9 +13,9 @@ public LocalDateTime(DateTimeOffset dateTimeOffset, TimeZoneInfo timeZoneInfo)

public LocalDateTime(DateTime dateTime, TimeZoneInfo timeZoneInfo)

Check warning on line 14 in DotNetThoughts.LocalTimeKit/LocalDateTime.cs

View workflow job for this annotation

GitHub Actions / create_nuget

Missing XML comment for publicly visible type or member 'LocalDateTime.LocalDateTime(DateTime, TimeZoneInfo)'
{
if (!((dateTime.Kind == DateTimeKind.Local && timeZoneInfo == TimeZoneInfo.Local)
|| (dateTime.Kind == DateTimeKind.Utc && timeZoneInfo == TimeZoneInfo.Utc)
|| (dateTime.Kind == DateTimeKind.Unspecified && timeZoneInfo != TimeZoneInfo.Local)))
if (!(dateTime.Kind == DateTimeKind.Local && timeZoneInfo == TimeZoneInfo.Local
|| dateTime.Kind == DateTimeKind.Utc && timeZoneInfo == TimeZoneInfo.Utc
|| dateTime.Kind == DateTimeKind.Unspecified && timeZoneInfo != TimeZoneInfo.Local))
{
throw new ArgumentException("Invalid combinations of datetime kinds and timezoneinfo");
}
Expand Down
12 changes: 6 additions & 6 deletions DotNetThoughts.sln
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ReadMe.md = ReadMe.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetThoughts.TimeTraveler", "DotNetThoughts.TimeTraveler\DotNetThoughts.TimeTraveler.csproj", "{9FF5D22F-49F9-4EDC-814D-5F89C86AB63E}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetThoughts.LocalTimeKit", "DotNetThoughts.LocalTimeKit\DotNetThoughts.LocalTimeKit.csproj", "{03DA1023-FDF4-4EF5-8951-19806434F8CA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -102,10 +102,10 @@ Global
{E0E86A0B-F4CE-4E88-99CF-C54AFC1C0C58}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0E86A0B-F4CE-4E88-99CF-C54AFC1C0C58}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0E86A0B-F4CE-4E88-99CF-C54AFC1C0C58}.Release|Any CPU.Build.0 = Release|Any CPU
{9FF5D22F-49F9-4EDC-814D-5F89C86AB63E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9FF5D22F-49F9-4EDC-814D-5F89C86AB63E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9FF5D22F-49F9-4EDC-814D-5F89C86AB63E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9FF5D22F-49F9-4EDC-814D-5F89C86AB63E}.Release|Any CPU.Build.0 = Release|Any CPU
{03DA1023-FDF4-4EF5-8951-19806434F8CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03DA1023-FDF4-4EF5-8951-19806434F8CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{03DA1023-FDF4-4EF5-8951-19806434F8CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03DA1023-FDF4-4EF5-8951-19806434F8CA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -122,7 +122,7 @@ Global
{66DCA5D2-4A06-4F1A-8DBB-36118CC01A34} = {BECD3795-EDD5-459E-BFCC-017082E1C34D}
{3D9F5F06-E09D-46B4-8058-1458467E0252} = {BECD3795-EDD5-459E-BFCC-017082E1C34D}
{E0E86A0B-F4CE-4E88-99CF-C54AFC1C0C58} = {BECD3795-EDD5-459E-BFCC-017082E1C34D}
{9FF5D22F-49F9-4EDC-814D-5F89C86AB63E} = {695E363E-055E-4ED5-9613-587E02A67578}
{03DA1023-FDF4-4EF5-8951-19806434F8CA} = {695E363E-055E-4ED5-9613-587E02A67578}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CAA5B6BA-B6C8-4A90-B9E6-D7634295532E}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\DotNetThoughts.LocalTimeKit\DotNetThoughts.LocalTimeKit.csproj" />
<ProjectReference Include="..\DotNetThoughts.TimeKeeping\DotNetThoughts.TimeKeeping.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@page "/timer"
@using DotNetThoughts.LocalTimeKit

<PageTitle>Timing</PageTitle>

Expand Down
3 changes: 3 additions & 0 deletions TimeKeeping/DotNetThoughts.TimeKeeping.App/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,9 @@
"System.Text.Encodings.Web": "8.0.0"
}
},
"dotnetthoughts.localtimekit": {
"type": "Project"
},
"dotnetthoughts.timekeeping": {
"type": "Project"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<ProjectReference Include="..\..\DotNetThoughts.LocalTimeKit\DotNetThoughts.LocalTimeKit.csproj" />
<ProjectReference Include="..\DotNetThoughts.TimeKeeping\DotNetThoughts.TimeKeeping.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace DotNetThoughts.TimeKeeping.Tests;
using DotNetThoughts.LocalTimeKit;

namespace DotNetThoughts.TimeKeeping.Tests;
public class LocalDateTimeTests
{

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@
"xunit.extensibility.core": "[2.8.1]"
}
},
"dotnetthoughts.localtimekit": {
"type": "Project"
},
"dotnetthoughts.timekeeping": {
"type": "Project"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>1.1.0</Version>
<Version>1.2.0</Version>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
Expand Down
1 change: 0 additions & 1 deletion TimeKeeping/DotNetThoughts.TimeKeeping/SystemTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

/// <summary>
/// "Mockable" DateTime that you still can use statically using the ambient context anti-pattern. Let's see how it rolls.
/// Replace with an IDateTime if problems arise.
/// </summary>
public class SystemTime
{
Expand Down
138 changes: 138 additions & 0 deletions TimeKeeping/DotNetThoughts.TimeKeeping/TimeTravelersClock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
namespace DotNetThoughts.TimeKeeping;

public class TimeTravelersClock
{
public DateTimeOffset? FreezedAt { get; set; }
public DateTimeOffset? Frozen { get; set; }
public TimeSpan Offset { get; set; } = TimeSpan.Zero;

public bool IsFrozen()
{
using var context = new OperationContext();
return FreezedAt != null;
}

public DateTimeOffset Reset()
{
using var context = new OperationContext();
Frozen = null;
FreezedAt = null;
Offset = TimeSpan.Zero;
return UtcNow();
}

public DateTimeOffset Thaw()
{
using var context = new OperationContext();
if (FreezedAt == null)
{
throw new InvalidOperationException("Cannot thaw when not frozen");
}
Offset = Offset.Add(-RealTimeFrozen());
FreezedAt = null;
Frozen = null;
return UtcNow();
}

public DateTimeOffset Freeze()
{
using var context = new OperationContext();
FreezedAt = context.UtcNow();
Frozen = UtcNow();
return Frozen.Value;
}

public DateTimeOffset Freeze(DateTimeOffset baseLine)
{
using var context = new OperationContext();
Reset();
SetBaseline(baseLine);
FreezedAt = context.UtcNow();
Frozen = UtcNow();
return Frozen.Value;
}

public DateTimeOffset UtcNow()
{
using var context = new OperationContext();
return Frozen ?? context.UtcNow().Add(Offset);
}

public DateTimeOffset AdvanceDays(double days)
{
using var context = new OperationContext();
return Advance(TimeSpan.FromDays(days));
}

public DateTimeOffset Advance(TimeSpan timeSpan)
{
using var context = new OperationContext();
Offset = Offset.Add(timeSpan);
if (IsFrozen())
{
Frozen = Frozen!.Value.Add(timeSpan);
}
return UtcNow();
}

public DateTimeOffset SetBaseline(DateTimeOffset baseLine)
{
if (IsFrozen()) throw new InvalidOperationException();
using var context = new OperationContext();
Offset = baseLine - context.UtcNow();
return UtcNow();
}

public DateTimeOffset SetOffset(TimeSpan offset)
{
if (IsFrozen()) throw new InvalidOperationException();
using var context = new OperationContext();
Offset = offset;

return UtcNow();
}

private TimeSpan RealTimeFrozen()
{
using var context = new OperationContext();
return FreezedAt != null ? context.UtcNow() - FreezedAt.Value : TimeSpan.Zero;
}

internal void From(TimeTravelersClock xSystemTime)
{
using var context = new OperationContext();
Offset = xSystemTime.Offset;
FreezedAt = xSystemTime.FreezedAt;
Frozen = xSystemTime.Frozen;
}

internal bool IsManipulated()
{
return Offset != TimeSpan.Zero || FreezedAt != null;
}

internal class OperationContext : IDisposable
{
private static AsyncLocal<DateTimeOffset?> _operationNow = new AsyncLocal<DateTimeOffset?>();

private bool _shouldReset = false;

public OperationContext()
{
if (_operationNow.Value == null)
{
_operationNow.Value = DateTimeOffset.UtcNow;
_shouldReset = true;
}
}
public void Dispose()
{
if (_shouldReset)
{
_operationNow.Value = null;
}
}

public DateTimeOffset UtcNow() => _operationNow.Value!.Value;
}
}

0 comments on commit 97406d5

Please sign in to comment.