Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
mattiasnordqvist committed Oct 29, 2024
2 parents cd3a709 + ce84ebb commit ead8b6c
Show file tree
Hide file tree
Showing 24 changed files with 373 additions and 90 deletions.
6 changes: 6 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup Condition="Exists('$(MSBuildProjectDirectory)\ReadMe.md')">
<PackageReadmeFile>ReadMe.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup Condition="Exists('$(MSBuildProjectDirectory)\ReadMe.md')">
<None Include="ReadMe.md" Pack="true" PackagePath="\"/>
</ItemGroup>
<ItemGroup Condition="$(MSBuildProjectName.EndsWith('Tests'))">
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
Expand Down
30 changes: 16 additions & 14 deletions DotNetThoughts.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetThoughts.TimeKeeping.Tests", "TimeKeeping\DotNetThoughts.TimeKeeping.Tests\DotNetThoughts.TimeKeeping.Tests.csproj", "{DF62C221-71AD-49A7-A9D8-48E31F06E27B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TimeKeeping", "TimeKeeping", "{695E363E-055E-4ED5-9613-587E02A67578}"
ProjectSection(SolutionItems) = preProject
ReadMe.md = ReadMe.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetThoughts.LocalTimeKit", "TimeKeeping\DotNetThoughts.LocalTimeKit\DotNetThoughts.LocalTimeKit.csproj", "{03DA1023-FDF4-4EF5-8951-19806434F8CA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetThoughts.Results", "Results\DotNetThoughts.Results\DotNetThoughts.Results.csproj", "{7032EE8C-FC18-4610-B7D6-613E552C278D}"
EndProject
Expand All @@ -33,9 +28,6 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetThoughts.Results.Analyzer.Package", "Results\DotNetThoughts.Results.Analyzer\DotNetThoughts.Results.Analyzer.Package\DotNetThoughts.Results.Analyzer.Package.csproj", "{E0E86A0B-F4CE-4E88-99CF-C54AFC1C0C58}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Results", "Results", "{BECD3795-EDD5-459E-BFCC-017082E1C34D}"
ProjectSection(SolutionItems) = preProject
Results\ReadMe.md = Results\ReadMe.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UserSecrets", "UserSecrets", "{BC7FC0EC-0CDC-4B88-A60C-BC920712841B}"
ProjectSection(SolutionItems) = preProject
Expand All @@ -52,7 +44,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ReadMe.md = ReadMe.md
EndProjectSection
EndProject

Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LocalTimeKit", "LocalTimeKit", "{11FA58AF-0B7C-4465-8448-AA710D5725AA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetThoughts.LocalTimeKit", "LocalTimeKit\DotNetThoughts.LocalTimeKit\DotNetThoughts.LocalTimeKit.csproj", "{0F5838D8-AC76-4C87-8DB6-6AE8140397A8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetThoughts.LocalTimeKit.Tests", "LocalTimeKit\DotNetThoughts.LocalTimeKit.Tests\DotNetThoughts.LocalTimeKit.Tests.csproj", "{BA3C3301-7D35-4828-8F00-736CDDEBC800}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -103,10 +100,14 @@ 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
{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
{0F5838D8-AC76-4C87-8DB6-6AE8140397A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0F5838D8-AC76-4C87-8DB6-6AE8140397A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0F5838D8-AC76-4C87-8DB6-6AE8140397A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0F5838D8-AC76-4C87-8DB6-6AE8140397A8}.Release|Any CPU.Build.0 = Release|Any CPU
{BA3C3301-7D35-4828-8F00-736CDDEBC800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BA3C3301-7D35-4828-8F00-736CDDEBC800}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA3C3301-7D35-4828-8F00-736CDDEBC800}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA3C3301-7D35-4828-8F00-736CDDEBC800}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -123,7 +124,8 @@ 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}
{03DA1023-FDF4-4EF5-8951-19806434F8CA} = {695E363E-055E-4ED5-9613-587E02A67578}
{0F5838D8-AC76-4C87-8DB6-6AE8140397A8} = {11FA58AF-0B7C-4465-8448-AA710D5725AA}
{BA3C3301-7D35-4828-8F00-736CDDEBC800} = {11FA58AF-0B7C-4465-8448-AA710D5725AA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CAA5B6BA-B6C8-4A90-B9E6-D7634295532E}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

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

</Project>
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
using DotNetThoughts.LocalTimeKit;

namespace DotNetThoughts.TimeKeeping.Tests;
namespace DotNetThoughts.LocalTimeKit.Tests;
public class LocalDateTimeTests
{

[Fact]
public void TestLocalDateTimeOffset()
{
var t = new DateTime(2024,06,06, 0, 0, 0, DateTimeKind.Unspecified);
var t = new DateTime(2024, 06, 06, 0, 0, 0, DateTimeKind.Unspecified);
var tz = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
var ldt = new LocalDateTime(t, tz);
var expectedDateTimeOffset = DateTimeOffset.Parse("2024-06-06T00:00:00+02:00");
Expand Down Expand Up @@ -67,7 +65,7 @@ public void TestDateConstructor()
var tz = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
var ldt = new LocalDateTime(t, tz);
var ldt2 = new LocalDateTime(d, tz);

ldt.DateTime.Should().Be(ldt2.DateTime);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

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

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,40 @@
/// </summary>
public readonly record struct LocalDateTime
{
/// <summary>
/// Creates a LocalDateTime from a DateOnly and a TimeZoneInfo
/// The date represents midnight in the given timezone
///
/// See <see cref="LocalDateTime(DateTime, TimeZoneInfo)"/>
/// </summary>
/// <param name="date"></param>
/// <param name="timeZoneInfo"></param>
public LocalDateTime(DateOnly date, TimeZoneInfo timeZoneInfo)
: this(date.ToDateTime(TimeOnly.MinValue), timeZoneInfo) { }

/// <summary>
/// Creates a LocalDateTime from a DateTimeOffset and a TimeZoneInfo
///
/// See <see cref="LocalDateTime(DateTime, TimeZoneInfo)"/>
/// </summary>
/// <param name="dateTimeOffset"></param>
/// <param name="timeZoneInfo"></param>
public LocalDateTime(DateTimeOffset dateTimeOffset, TimeZoneInfo timeZoneInfo)
: this(TimeZoneInfo.ConvertTime(dateTimeOffset, timeZoneInfo).DateTime, timeZoneInfo) { }

/// <summary>
/// Creates a LocalDateTime from a DateTime and a TimeZoneInfo
/// If the datetime has DateTimeKind.Local, the timezone must be TimeZoneInfo.Local
/// If the datetime has DateTimeKind.Utc, the timezone must be TimeZoneInfo.Utc
/// Otherwise, the timezone must not be TimeZoneInfo.Local
/// In any of the cases above, an ArgumentException is thrown.
///
/// Some times are invalid for some timezones, and some times are ambiguous.
/// Any such time and timezone combination will throw an ArgumentException.
/// </summary>
/// <param name="dateTime"></param>
/// <param name="timeZoneInfo"></param>
/// <exception cref="ArgumentException"></exception>
public LocalDateTime(DateTime dateTime, TimeZoneInfo timeZoneInfo)
{
if (!(dateTime.Kind == DateTimeKind.Local && timeZoneInfo == TimeZoneInfo.Local
Expand All @@ -37,32 +65,57 @@ public LocalDateTime(DateTime dateTime, TimeZoneInfo timeZoneInfo)
public DateTime DateTime { get; }

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

View workflow job for this annotation

GitHub Actions / create_nuget

Missing XML comment for publicly visible type or member 'LocalDateTime.DateTime'

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

View workflow job for this annotation

GitHub Actions / create_nuget

Missing XML comment for publicly visible type or member 'LocalDateTime.DateTime'
public TimeZoneInfo TimeZoneInfo { get; }

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

View workflow job for this annotation

GitHub Actions / create_nuget

Missing XML comment for publicly visible type or member 'LocalDateTime.TimeZoneInfo'

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

View workflow job for this annotation

GitHub Actions / create_nuget

Missing XML comment for publicly visible type or member 'LocalDateTime.TimeZoneInfo'

/// <summary>
/// Returns a new LocalDateTime representing the same instance in time, but in relation to a different time zone.
/// </summary>
/// <param name="newTz"></param>
/// <returns></returns>
public LocalDateTime ToTimeZone(TimeZoneInfo newTz)
{
return new LocalDateTime(TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo, newTz), newTz);
}

/// <summary>
/// Returns a new LocalDateTime representing the midnight of the current date.
/// </summary>
/// <returns></returns>
public LocalDateTime ToMidnight()
{
return new LocalDateTime(DateTime.Date, TimeZoneInfo);
}

/// <summary>
/// Returns a new LocalDateTime representing the beginning of the current year.
/// </summary>
/// <returns></returns>
public LocalDateTime ToBeginningOfYear()
{
return new LocalDateTime(new DateTime(DateTime.Year, 1, 1), TimeZoneInfo);
}

/// <summary>
/// Returns a new LocalDateTime representing the end of the current year.
/// </summary>
/// <returns></returns>
public LocalDateTime ToEndOfYear()
{
return new LocalDateTime(new DateTime(DateTime.Year, 12, 31, 23, 59, 59, 999, 999), TimeZoneInfo);
}

/// <summary>
/// Returns a DateTimeOffset, with offset 0, representing this instance in time.
/// </summary>
/// <returns></returns>
public DateTimeOffset ToDateTimeOffsetUtc()
{
var shouldHaveHadKindUtc = TimeZoneInfo.ConvertTimeToUtc(DateTime, TimeZoneInfo);
return shouldHaveHadKindUtc;
}

/// <summary>
/// Returns a DateTimeOffset, with offset matching the current timezone, representing this instance in time.
/// </summary>
/// <returns></returns>
public DateTimeOffset ToDateTimeOffsetLocal()
{
return new DateTimeOffset(DateTime, TimeZoneInfo.GetUtcOffset(DateTime));
Expand Down
14 changes: 14 additions & 0 deletions LocalTimeKit/DotNetThoughts.LocalTimeKit/ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Local Time Kit

## LocalDateTime

`LocalDateTime` is an unambiguous representation of an instance in time.
Types like `DateTime` and `DateOnly` does not provide enough information to determine exactly what instance in time they represent. LocalDateTime aims to package all you need into one type.

Don't worry about the word "Local" in the name. LocalDateTime is not limited to local instances in time in the normal sense. LocalDateTime consider even a UTC date to be local. Local to the utc time zone.

While .Net has a lot of shady "helpful" implicit conversions between `DateTime` and `DateTimeOffset`, LocalDateTime is explicit about what it does.

No time-operations, makes any sense without knowing which timezone you are operating in. Remember, daylight savings have the effect of some days lasting only 23 hours, while others last 25.
LocalDateTime therefor requires you to specify a timezone when you create an instance.
LocalDateTime then helps you to convert between timezones, and to calculate timezone-related specific instances of time, like beginning of year, or midnight of current day etc.
13 changes: 11 additions & 2 deletions ReadMe.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
# Results
[Results/ReadMe.md](Results/ReadMe.md)
[Results/DotNetThoughts.Results/ReadMe.md](Results/DotNetThoughts.Results/ReadMe.md)

# Results.Validation
[Results/DotNetThoughts.Results.Validation/ReadMe.md](Results/DotNetThoughts.Results.Validation/ReadMe.md)

# Results.Json
[Results/DotNetThoughts.Results.Json/ReadMe.md](Results/DotNetThoughts.Results.Json/ReadMe.md)

# TimeKeeping
[TimeKeeping/ReadMe.md](TimeKeeping/ReadMe.md)
[TimeKeeping/DotNetThoughts.TimeKeeping/ReadMe.md](TimeKeeping/DotNetThoughts.TimeKeeping/ReadMe.md)

# LocalDateTime
[LocalDateTime/DotNetThoughts.LocalTimeKit/ReadMe.md](LocalDateTime/DotNetThoughts.LocalTimeKit/ReadMe.md)

# UserSecrets
[UserSecrets/ReadMe.md](UserSecrets/ReadMe.md)
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
"dotnetthoughts.results.json": {
"type": "Project",
"dependencies": {
"DotNetThoughts.Results": "[1.5.7, )"
"DotNetThoughts.Results": "[1.5.9, )"
}
},
"DotNetThoughts.Results.Analyzer": {
Expand Down
36 changes: 36 additions & 0 deletions Results/DotNetThoughts.Results.Json/ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Results.Json

Package contains code to help serialize and deserialize Result objects to and from JSON.
`JsonConverterFactoryForResultOfT` is a `JsonConverterFactory` that can create `JsonConverter` objects for any `Result<T>` object.
Remember, a Result representing one or more Errors contains a list of objects implementing the `IError` interface.
The actual type of an Error object is not included when serialized. This means, that when deserializing that Error again, it can't be deserialized to its original type.
Instead, the Error object is deserialized to a generic `DeserializedError` object.

A serialized _Successful_ `Result<T>` will look like this:
```json
{
"Success": true,
"Value": "Some value"
}
```
A serialized _Successful_ `Result<Unit>` will look like this:
```json
{
"Success": true
}
```
A serialized _Error_ `Result<T>` or `Result<Unit>` will look like this:
```json
{
"Success": false,
"Errors": [
{
"Type": "MyError",
"Message": "Some error message"
"Data": {
"Key": "value",
}
}
]
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
"dotnetthoughts.results.validation": {
"type": "Project",
"dependencies": {
"DotNetThoughts.Results": "[1.5.7, )"
"DotNetThoughts.Results": "[1.5.9, )"
}
},
"DotNetThoughts.Results.Analyzer": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>$(DefineConstants);CONTRACTS_FULL</DefineConstants>
</PropertyGroup>
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
</ItemGroup>

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

Expand Down
4 changes: 2 additions & 2 deletions TimeKeeping/DotNetThoughts.TimeKeeping.App/Pages/Timer.razor
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@

private void UpdateUI()
{
systemTime = clock.UtcNow();
systemTime = clock.Now();
realTime = DateTimeOffset.UtcNow;
localSystemTime = new LocalDateTime(systemTime.DateTime, TimeZoneInfo.Utc).ToTimeZone(TimeZoneInfo.Local).ToDateTimeOffsetLocal();
nairobiLocalSystemTime = new LocalDateTime(systemTime.DateTime, TimeZoneInfo.Utc).ToTimeZone(TimeZoneInfo.FindSystemTimeZoneById(selectedTimeZone)).ToDateTimeOffsetLocal();
Expand Down Expand Up @@ -139,7 +139,7 @@

private void SetBaseLine()
{
clock.SetBaseline(new DateTimeOffset(2021, 1, 1, 0, 0, 0, TimeSpan.Zero));
clock.SetNow(new DateTimeOffset(2021, 1, 1, 0, 0, 0, TimeSpan.Zero));
UpdateUI();

}
Expand Down
12 changes: 6 additions & 6 deletions TimeKeeping/DotNetThoughts.TimeKeeping.App/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@
},
"Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[8.0.6, )",
"resolved": "8.0.6",
"contentHash": "E+lDylsTeP4ZiDmnEkiJ5wobnGaIJzFhOgZppznJCb69UZgbh6G3cfv1pnLDLLBx6JAgl0kAlnINDeT3uCuczQ=="
"requested": "[8.0.8, )",
"resolved": "8.0.8",
"contentHash": "P8wR6MUWwYXIjPJuBaZgo5zlI/GWI6QEAo6NyVIbPefa9CCkohYu7dP2rD/mrqnjEqfRHyl+h9VZrDoGpELqYg=="
},
"Microsoft.NET.Sdk.WebAssembly.Pack": {
"type": "Direct",
"requested": "[8.0.5, )",
"resolved": "8.0.5",
"contentHash": "CABBOqZZEDgiVSjkwUr+pJEGEtQbrT+6dltzJnBDap7mOSvfn53+zwb112hRGB7ynm9ikAocGZTUp+GizbH7XQ=="
"requested": "[8.0.8, )",
"resolved": "8.0.8",
"contentHash": "z2UxqxjssvxlcQ68KZorgQDITdV2u5H6CWOGhs3kiv+qqDtokhDpcK660TUMrX+FTDdRKie0l7EeZEdej26Ycw=="
},
"Microsoft.AspNetCore.Authorization": {
"type": "Transitive",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">

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

Expand Down
Loading

0 comments on commit ead8b6c

Please sign in to comment.