diff --git a/Fluxera.Temporal.sln b/Fluxera.Temporal.sln
new file mode 100644
index 0000000..6b1f610
--- /dev/null
+++ b/Fluxera.Temporal.sln
@@ -0,0 +1,63 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31919.166
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".items", ".items", "{75AC41E9-2B8B-4D76-A7DF-A18F4FB9D6D6}"
+ ProjectSection(SolutionItems) = preProject
+ .gitignore = .gitignore
+ azure-pipelines.yml = azure-pipelines.yml
+ GitVersion.yml = GitVersion.yml
+ global.json = global.json
+ icon.png = icon.png
+ LICENSE = LICENSE
+ README.md = README.md
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DF28D730-99B3-4811-AAC7-725A73B3F668}"
+ ProjectSection(SolutionItems) = preProject
+ src\Directory.Build.props = src\Directory.Build.props
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{F18D2D58-282C-4D93-8D9A-3A76CF98F018}"
+ ProjectSection(SolutionItems) = preProject
+ tests\Directory.Build.props = tests\Directory.Build.props
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluxera.Temporal", "src\Fluxera.Temporal\Fluxera.Temporal.csproj", "{00724D4C-75EF-4EA2-B5F9-0922B948021B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fluxera.Temporal.MongoDB", "src\Fluxera.Temporal.MongoDB\Fluxera.Temporal.MongoDB.csproj", "{D1674A18-F0B2-43EF-9C6B-C541B40A7F73}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fluxera.Temporal.MongoDB.UnitTests", "tests\Fluxera.Temporal.MongoDB.UnitTests\Fluxera.Temporal.MongoDB.UnitTests.csproj", "{309830E5-238E-4BF4-A9BA-F942D30EE764}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {00724D4C-75EF-4EA2-B5F9-0922B948021B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {00724D4C-75EF-4EA2-B5F9-0922B948021B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {00724D4C-75EF-4EA2-B5F9-0922B948021B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {00724D4C-75EF-4EA2-B5F9-0922B948021B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D1674A18-F0B2-43EF-9C6B-C541B40A7F73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D1674A18-F0B2-43EF-9C6B-C541B40A7F73}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D1674A18-F0B2-43EF-9C6B-C541B40A7F73}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D1674A18-F0B2-43EF-9C6B-C541B40A7F73}.Release|Any CPU.Build.0 = Release|Any CPU
+ {309830E5-238E-4BF4-A9BA-F942D30EE764}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {309830E5-238E-4BF4-A9BA-F942D30EE764}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {309830E5-238E-4BF4-A9BA-F942D30EE764}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {309830E5-238E-4BF4-A9BA-F942D30EE764}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {00724D4C-75EF-4EA2-B5F9-0922B948021B} = {DF28D730-99B3-4811-AAC7-725A73B3F668}
+ {D1674A18-F0B2-43EF-9C6B-C541B40A7F73} = {DF28D730-99B3-4811-AAC7-725A73B3F668}
+ {309830E5-238E-4BF4-A9BA-F942D30EE764} = {F18D2D58-282C-4D93-8D9A-3A76CF98F018}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {D97BF2AF-6E68-4E88-BF70-773A86E26013}
+ EndGlobalSection
+EndGlobal
diff --git a/GitVersion.yml b/GitVersion.yml
new file mode 100644
index 0000000..0093d88
--- /dev/null
+++ b/GitVersion.yml
@@ -0,0 +1 @@
+mode: Mainline
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
new file mode 100644
index 0000000..6262d04
--- /dev/null
+++ b/azure-pipelines.yml
@@ -0,0 +1,58 @@
+# CI pipeline for a NuGet package solution.
+
+trigger:
+ branches:
+ include: [ '*' ]
+ exclude: [ 'refs/tags/*' ]
+
+variables:
+ BuildConfiguration: Release
+ DotNetCoreVersion: 6.0.201
+
+stages:
+- stage: BuildAndTest
+ jobs:
+ - job: BuildAndTest
+ pool:
+ name: Default
+ steps:
+ - checkout: self
+ persistCredentials: 'true'
+ clean: true
+ # Install the desired .NET SDK.
+ - task: UseDotNet@2
+ displayName: 'Acquire .NET SDK'
+ inputs:
+ packageType: 'sdk'
+ version: $(DotNetCoreVersion)
+ includePreviewVersions: false
+ # Build all projects.
+ - task: DotNetCoreCLI@2
+ displayName: 'Build Projects'
+ inputs:
+ projects: '**/*.csproj'
+ arguments: '--configuration $(BuildConfiguration)'
+ # Run all available tests.
+ - task: DotNetCoreCLI@2
+ displayName: 'Execute Tests'
+ inputs:
+ command: test
+ projects: '**/*Tests/*.csproj'
+ arguments: '--configuration $(BuildConfiguration)'
+ nobuild: true
+ # Create the NuGet packages.
+ - task: DotNetCoreCLI@2
+ displayName: 'Pack Packages'
+ inputs:
+ command: 'pack'
+ packagesToPack: 'src/**/*.csproj'
+ nobuild: true
+ verbosityPack: Minimal
+ includesymbols: false
+ # Copy created NuGet packages to the builds artifacts directory.
+ - task: PublishBuildArtifacts@1
+ displayName: 'Publish Package Artifacts'
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)'
+ ArtifactName: 'drop'
+ publishLocation: 'Container'
\ No newline at end of file
diff --git a/global.json b/global.json
new file mode 100644
index 0000000..726ce1b
--- /dev/null
+++ b/global.json
@@ -0,0 +1,5 @@
+{
+ "sdk": {
+ "version": "6.0.201"
+ }
+}
\ No newline at end of file
diff --git a/icon.png b/icon.png
new file mode 100644
index 0000000..f35c53b
Binary files /dev/null and b/icon.png differ
diff --git a/src/.gitkeep b/src/.gitkeep
new file mode 100644
index 0000000..5f28270
--- /dev/null
+++ b/src/.gitkeep
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
new file mode 100644
index 0000000..1721285
--- /dev/null
+++ b/src/Directory.Build.props
@@ -0,0 +1,36 @@
+
+
+
+ latest
+ enable
+ disable
+ true
+ true
+
+
+
+ Fluxera Software Development GmbH
+ Fluxera Software Foundation
+ Copyright © 2014-2022 Fluxera Software Development GmbH. All rights reserved.
+
+
+
+ Matthias Gernand
+ https://github.com/fluxera/Fluxera.Guard
+ https://github.com/fluxera/Fluxera.Guard
+ icon.png
+ README.md
+ false
+ false
+ en
+ git
+ MIT
+ true
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Fluxera.Temporal.MongoDB/ConventionPackExtensions.cs b/src/Fluxera.Temporal.MongoDB/ConventionPackExtensions.cs
new file mode 100644
index 0000000..f762335
--- /dev/null
+++ b/src/Fluxera.Temporal.MongoDB/ConventionPackExtensions.cs
@@ -0,0 +1,20 @@
+namespace Fluxera.Temporal.MongoDB
+{
+ using global::MongoDB.Bson.Serialization.Conventions;
+ using JetBrains.Annotations;
+
+ [PublicAPI]
+ public static class ConventionPackExtensions
+ {
+ public static ConventionPack UseTemporal(this ConventionPack pack)
+ {
+ pack.Add(new DateTimeConvention());
+ pack.Add(new DateTimeOffsetConvention());
+ pack.Add(new DateOnlyConvention());
+ pack.Add(new TimeOnlyConvention());
+ pack.Add(new TimeSpanConvention());
+
+ return pack;
+ }
+ }
+}
diff --git a/src/Fluxera.Temporal.MongoDB/DateOnlyConvention.cs b/src/Fluxera.Temporal.MongoDB/DateOnlyConvention.cs
new file mode 100644
index 0000000..8673ff7
--- /dev/null
+++ b/src/Fluxera.Temporal.MongoDB/DateOnlyConvention.cs
@@ -0,0 +1,29 @@
+namespace Fluxera.Temporal.MongoDB
+{
+ using System;
+ using Fluxera.Utilities.Extensions;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Conventions;
+ using global::MongoDB.Bson.Serialization.Serializers;
+
+ internal sealed class DateOnlyConvention : ConventionBase, IMemberMapConvention
+ {
+ ///
+ public void Apply(BsonMemberMap memberMap)
+ {
+ Type originalMemberType = memberMap.MemberType;
+ Type memberType = originalMemberType.UnwrapNullableType();
+
+ if(memberType == typeof(DateOnly))
+ {
+ DateOnlySerializer dateOnlySerializer = new DateOnlySerializer();
+
+ IBsonSerializer serializer = originalMemberType.IsNullable()
+ ? new NullableSerializer(dateOnlySerializer)
+ : dateOnlySerializer;
+
+ memberMap.SetSerializer(serializer);
+ }
+ }
+ }
+}
diff --git a/src/Fluxera.Temporal.MongoDB/DateOnlyDateTimeOffsetSerializer.cs b/src/Fluxera.Temporal.MongoDB/DateOnlyDateTimeOffsetSerializer.cs
new file mode 100644
index 0000000..73afcce
--- /dev/null
+++ b/src/Fluxera.Temporal.MongoDB/DateOnlyDateTimeOffsetSerializer.cs
@@ -0,0 +1,31 @@
+namespace Fluxera.Temporal.MongoDB
+{
+ using System;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Serializers;
+ using JetBrains.Annotations;
+
+ [PublicAPI]
+ public class DateOnlyDateTimeOffsetSerializer : DateTimeOffsetSerializer
+ {
+ private readonly DateTimeSerializer dateTimeSerializer;
+
+ public DateOnlyDateTimeOffsetSerializer(DateTimeSerializer dateTimeSerializer)
+ {
+ this.dateTimeSerializer = dateTimeSerializer;
+ }
+
+ ///
+ public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, DateTimeOffset value)
+ {
+ this.dateTimeSerializer.Serialize(context, args, value.Date);
+ }
+
+ ///
+ public override DateTimeOffset Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
+ {
+ DateTimeOffset dateTimeOffset = this.dateTimeSerializer.Deserialize(context, args);
+ return dateTimeOffset.Date;
+ }
+ }
+}
diff --git a/src/Fluxera.Temporal.MongoDB/DateOnlyDateTimeSerializer.cs b/src/Fluxera.Temporal.MongoDB/DateOnlyDateTimeSerializer.cs
new file mode 100644
index 0000000..9b8434f
--- /dev/null
+++ b/src/Fluxera.Temporal.MongoDB/DateOnlyDateTimeSerializer.cs
@@ -0,0 +1,31 @@
+namespace Fluxera.Temporal.MongoDB
+{
+ using System;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Serializers;
+ using JetBrains.Annotations;
+
+ [PublicAPI]
+ public class DateOnlyDateTimeSerializer : DateTimeSerializer
+ {
+ private readonly DateTimeSerializer dateTimeSerializer;
+
+ public DateOnlyDateTimeSerializer(DateTimeSerializer dateTimeSerializer)
+ {
+ this.dateTimeSerializer = dateTimeSerializer;
+ }
+
+ ///
+ public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, DateTime value)
+ {
+ this.dateTimeSerializer.Serialize(context, args, value.Date);
+ }
+
+ ///
+ public override DateTime Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
+ {
+ DateTime dateTime = this.dateTimeSerializer.Deserialize(context, args);
+ return dateTime.Date;
+ }
+ }
+}
diff --git a/src/Fluxera.Temporal.MongoDB/DateOnlySerializer.cs b/src/Fluxera.Temporal.MongoDB/DateOnlySerializer.cs
new file mode 100644
index 0000000..f1cc6b7
--- /dev/null
+++ b/src/Fluxera.Temporal.MongoDB/DateOnlySerializer.cs
@@ -0,0 +1,21 @@
+namespace Fluxera.Temporal.MongoDB
+{
+ using System;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Serializers;
+ using JetBrains.Annotations;
+
+ [PublicAPI]
+ public class DateOnlySerializer : StructSerializerBase
+ {
+ public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, DateOnly value)
+ {
+ context.Writer.WriteString(value.ToString("yyyy-MM-dd"));
+ }
+
+ public override DateOnly Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
+ {
+ return DateOnly.ParseExact(context.Reader.ReadString(), "yyyy-MM-dd", null);
+ }
+ }
+}
diff --git a/src/Fluxera.Temporal.MongoDB/DateTimeConvention.cs b/src/Fluxera.Temporal.MongoDB/DateTimeConvention.cs
new file mode 100644
index 0000000..d35113a
--- /dev/null
+++ b/src/Fluxera.Temporal.MongoDB/DateTimeConvention.cs
@@ -0,0 +1,44 @@
+namespace Fluxera.Temporal.MongoDB
+{
+ using System;
+ using System.Reflection;
+ using Fluxera.ComponentModel.Annotations;
+ using Fluxera.Utilities.Extensions;
+ using global::MongoDB.Bson;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Conventions;
+ using global::MongoDB.Bson.Serialization.Serializers;
+
+ internal sealed class DateTimeConvention : ConventionBase, IMemberMapConvention
+ {
+ ///
+ public void Apply(BsonMemberMap memberMap)
+ {
+ Type originalMemberType = memberMap.MemberType;
+ Type memberType = Nullable.GetUnderlyingType(originalMemberType) ?? originalMemberType;
+ MemberInfo member = memberMap.MemberInfo;
+
+ if(memberType == typeof(DateTime))
+ {
+ bool dateOnly = member.IsDefined(typeof(DateOnlyAttribute));
+
+ BsonType representation = dateOnly ? BsonType.String : BsonType.Document;
+
+ DateTimeSerializer dateTimeSerializer = DateTimeSerializer.UtcInstance
+ .WithRepresentation(representation)
+ .WithDateOnly(dateOnly);
+
+ if(dateOnly)
+ {
+ dateTimeSerializer = new DateOnlyDateTimeSerializer(dateTimeSerializer);
+ }
+
+ IBsonSerializer serializer = originalMemberType.IsNullable()
+ ? new NullableSerializer(dateTimeSerializer)
+ : dateTimeSerializer;
+
+ memberMap.SetSerializer(serializer);
+ }
+ }
+ }
+}
diff --git a/src/Fluxera.Temporal.MongoDB/DateTimeOffsetConvention.cs b/src/Fluxera.Temporal.MongoDB/DateTimeOffsetConvention.cs
new file mode 100644
index 0000000..4123fae
--- /dev/null
+++ b/src/Fluxera.Temporal.MongoDB/DateTimeOffsetConvention.cs
@@ -0,0 +1,46 @@
+namespace Fluxera.Temporal.MongoDB
+{
+ using System;
+ using System.Reflection;
+ using Fluxera.ComponentModel.Annotations;
+ using Fluxera.Utilities.Extensions;
+ using global::MongoDB.Bson;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Conventions;
+ using global::MongoDB.Bson.Serialization.Serializers;
+
+ internal sealed class DateTimeOffsetConvention : ConventionBase, IMemberMapConvention
+ {
+ ///
+ public void Apply(BsonMemberMap memberMap)
+ {
+ Type originalMemberType = memberMap.MemberType;
+ Type memberType = originalMemberType.UnwrapNullableType();
+ MemberInfo member = memberMap.MemberInfo;
+
+ if(memberType == typeof(DateTimeOffset))
+ {
+ bool dateOnly = member.IsDefined(typeof(DateOnlyAttribute));
+
+ BsonType representation = dateOnly ? BsonType.String : BsonType.Document;
+
+ DateTimeOffsetSerializer dateTimeOffsetSerializer = new DateTimeOffsetSerializer(representation);
+
+ if(dateOnly)
+ {
+ DateTimeSerializer dateTimeSerializer = DateTimeSerializer.UtcInstance
+ .WithRepresentation(representation)
+ .WithDateOnly(true);
+
+ dateTimeOffsetSerializer = new DateOnlyDateTimeOffsetSerializer(dateTimeSerializer);
+ }
+
+ IBsonSerializer serializer = originalMemberType.IsNullable()
+ ? new NullableSerializer(dateTimeOffsetSerializer)
+ : dateTimeOffsetSerializer;
+
+ memberMap.SetSerializer(serializer);
+ }
+ }
+ }
+}
diff --git a/src/Fluxera.Temporal.MongoDB/Fluxera.Temporal.MongoDB.csproj b/src/Fluxera.Temporal.MongoDB/Fluxera.Temporal.MongoDB.csproj
new file mode 100644
index 0000000..6b50bf0
--- /dev/null
+++ b/src/Fluxera.Temporal.MongoDB/Fluxera.Temporal.MongoDB.csproj
@@ -0,0 +1,38 @@
+
+
+
+ net6.0
+
+
+
+ Fluxera.Temporal.MongoDB
+ A libary that provides serializer support for MongoDB for temporal types.
+ fluxera;library;temporal,json
+
+
+
+
+ true
+ \
+
+
+ true
+ \
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Fluxera.Temporal.MongoDB/TimeOnlyConvention.cs b/src/Fluxera.Temporal.MongoDB/TimeOnlyConvention.cs
new file mode 100644
index 0000000..d863bfc
--- /dev/null
+++ b/src/Fluxera.Temporal.MongoDB/TimeOnlyConvention.cs
@@ -0,0 +1,29 @@
+namespace Fluxera.Temporal.MongoDB
+{
+ using System;
+ using Fluxera.Utilities.Extensions;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Conventions;
+ using global::MongoDB.Bson.Serialization.Serializers;
+
+ internal sealed class TimeOnlyConvention : ConventionBase, IMemberMapConvention
+ {
+ ///
+ public void Apply(BsonMemberMap memberMap)
+ {
+ Type originalMemberType = memberMap.MemberType;
+ Type memberType = originalMemberType.UnwrapNullableType();
+
+ if(memberType == typeof(TimeOnly))
+ {
+ TimeOnlySerializer timeOnlySerializer = new TimeOnlySerializer();
+
+ IBsonSerializer serializer = originalMemberType.IsNullable()
+ ? new NullableSerializer(timeOnlySerializer)
+ : timeOnlySerializer;
+
+ memberMap.SetSerializer(serializer);
+ }
+ }
+ }
+}
diff --git a/src/Fluxera.Temporal.MongoDB/TimeOnlySerializer.cs b/src/Fluxera.Temporal.MongoDB/TimeOnlySerializer.cs
new file mode 100644
index 0000000..0531b46
--- /dev/null
+++ b/src/Fluxera.Temporal.MongoDB/TimeOnlySerializer.cs
@@ -0,0 +1,24 @@
+namespace Fluxera.Temporal.MongoDB
+{
+ using System;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Serializers;
+ using JetBrains.Annotations;
+
+ [PublicAPI]
+ public class TimeOnlySerializer : StructSerializerBase
+ {
+ private readonly TimeSpanSerializer timeSpanSerializer = new TimeSpanSerializer();
+
+ public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TimeOnly value)
+ {
+ this.timeSpanSerializer.Serialize(context, args, value.ToTimeSpan());
+ }
+
+ public override TimeOnly Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
+ {
+ TimeSpan timeSpan = this.timeSpanSerializer.Deserialize(context, args);
+ return TimeOnly.FromTimeSpan(timeSpan);
+ }
+ }
+}
diff --git a/src/Fluxera.Temporal.MongoDB/TimeSpanConvention.cs b/src/Fluxera.Temporal.MongoDB/TimeSpanConvention.cs
new file mode 100644
index 0000000..253110f
--- /dev/null
+++ b/src/Fluxera.Temporal.MongoDB/TimeSpanConvention.cs
@@ -0,0 +1,29 @@
+namespace Fluxera.Temporal.MongoDB
+{
+ using System;
+ using Fluxera.Utilities.Extensions;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Conventions;
+ using global::MongoDB.Bson.Serialization.Serializers;
+
+ internal sealed class TimeSpanConvention : ConventionBase, IMemberMapConvention
+ {
+ ///
+ public void Apply(BsonMemberMap memberMap)
+ {
+ Type originalMemberType = memberMap.MemberType;
+ Type memberType = originalMemberType.UnwrapNullableType();
+
+ if(memberType == typeof(TimeSpan))
+ {
+ TimeSpanSerializer timeSpanSerializer = new TimeSpanSerializer();
+
+ IBsonSerializer serializer = originalMemberType.IsNullable()
+ ? new NullableSerializer(timeSpanSerializer)
+ : timeSpanSerializer;
+
+ memberMap.SetSerializer(serializer);
+ }
+ }
+ }
+}
diff --git a/src/Fluxera.Temporal/Fluxera.Temporal.csproj b/src/Fluxera.Temporal/Fluxera.Temporal.csproj
new file mode 100644
index 0000000..0a967a0
--- /dev/null
+++ b/src/Fluxera.Temporal/Fluxera.Temporal.csproj
@@ -0,0 +1,34 @@
+
+
+
+ net6.0
+
+
+
+ Fluxera.Temporal
+ A libary that provides temporal types.
+ fluxera;library;temporal
+
+
+
+
+ true
+ \
+
+
+ true
+ \
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/.gitkeep b/tests/.gitkeep
new file mode 100644
index 0000000..5f28270
--- /dev/null
+++ b/tests/.gitkeep
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props
new file mode 100644
index 0000000..28e17f1
--- /dev/null
+++ b/tests/Directory.Build.props
@@ -0,0 +1,17 @@
+
+
+
+ latest
+ enable
+ disable
+ false
+ false
+
+
+
+ Fluxera Software Development GmbH
+ Fluxera Software Foundation
+ Copyright © 2014-2022 Fluxera Software Development GmbH. All rights reserved.
+
+
+
\ No newline at end of file
diff --git a/tests/Fluxera.Temporal.MongoDB.UnitTests/DateOnlyDateTimeOffsetTests.cs b/tests/Fluxera.Temporal.MongoDB.UnitTests/DateOnlyDateTimeOffsetTests.cs
new file mode 100644
index 0000000..2ca05b5
--- /dev/null
+++ b/tests/Fluxera.Temporal.MongoDB.UnitTests/DateOnlyDateTimeOffsetTests.cs
@@ -0,0 +1,56 @@
+namespace Fluxera.Temporal.MongoDB.UnitTests
+{
+ using System;
+ using FluentAssertions;
+ using Fluxera.ComponentModel.Annotations;
+ using global::MongoDB.Bson;
+ using global::MongoDB.Bson.IO;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Conventions;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class DateOnlyDateTimeOffsetTests : TestsBase
+ {
+ [SetUp]
+ public void SetUp()
+ {
+ ConventionPack pack = new ConventionPack();
+ pack.UseTemporal();
+ ConventionRegistry.Register("ConventionPack", pack, t => true);
+ }
+
+ private class TestClass
+ {
+ [DateOnly]
+ public DateTimeOffset Property { get; set; }
+ }
+
+ [Test]
+ public void ShouldDeserialize()
+ {
+ string json = @"{""Property"" : ""2022-04-01""}";
+ TestClass result = BsonSerializer.Deserialize(json);
+
+ result.Should().NotBeNull();
+ result.Property.Should().Be(new DateTime(2022, 4, 1));
+ }
+
+ [Test]
+ public void ShouldSerialize()
+ {
+ TestClass obj = new TestClass
+ {
+ Property = new DateTimeOffset(2022, 4, 1, 10, 0, 0, TimeSpan.FromHours(1))
+ };
+
+ string json = obj.ToJson(new JsonWriterSettings
+ {
+ Indent = true
+ });
+
+ Console.WriteLine(json);
+ json.Should().Contain(@"""2022-04-01""");
+ }
+ }
+}
diff --git a/tests/Fluxera.Temporal.MongoDB.UnitTests/DateOnlyDateTimeTests.cs b/tests/Fluxera.Temporal.MongoDB.UnitTests/DateOnlyDateTimeTests.cs
new file mode 100644
index 0000000..362e2fb
--- /dev/null
+++ b/tests/Fluxera.Temporal.MongoDB.UnitTests/DateOnlyDateTimeTests.cs
@@ -0,0 +1,56 @@
+namespace Fluxera.Temporal.MongoDB.UnitTests
+{
+ using System;
+ using FluentAssertions;
+ using Fluxera.ComponentModel.Annotations;
+ using global::MongoDB.Bson;
+ using global::MongoDB.Bson.IO;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Conventions;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class DateOnlyDateTimeTests : TestsBase
+ {
+ [SetUp]
+ public void SetUp()
+ {
+ ConventionPack pack = new ConventionPack();
+ pack.UseTemporal();
+ ConventionRegistry.Register("ConventionPack", pack, t => true);
+ }
+
+ private class TestClass
+ {
+ [DateOnly]
+ public DateTime Property { get; set; }
+ }
+
+ [Test]
+ public void ShouldDeserialize()
+ {
+ string json = @"{""Property"" : ""2022-04-01""}";
+ TestClass result = BsonSerializer.Deserialize(json);
+
+ result.Should().NotBeNull();
+ result.Property.Should().Be(new DateTime(2022, 4, 1));
+ }
+
+ [Test]
+ public void ShouldSerialize()
+ {
+ TestClass obj = new TestClass
+ {
+ Property = new DateTime(2022, 4, 1, 10, 0, 0)
+ };
+
+ string json = obj.ToJson(new JsonWriterSettings
+ {
+ Indent = true
+ });
+
+ Console.WriteLine(json);
+ json.Should().Contain(@"""2022-04-01""");
+ }
+ }
+}
diff --git a/tests/Fluxera.Temporal.MongoDB.UnitTests/DateOnlyTests.cs b/tests/Fluxera.Temporal.MongoDB.UnitTests/DateOnlyTests.cs
new file mode 100644
index 0000000..d5fc8b4
--- /dev/null
+++ b/tests/Fluxera.Temporal.MongoDB.UnitTests/DateOnlyTests.cs
@@ -0,0 +1,54 @@
+namespace Fluxera.Temporal.MongoDB.UnitTests
+{
+ using System;
+ using FluentAssertions;
+ using global::MongoDB.Bson;
+ using global::MongoDB.Bson.IO;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Conventions;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class DateOnlyTests : TestsBase
+ {
+ [SetUp]
+ public void SetUp()
+ {
+ ConventionPack pack = new ConventionPack();
+ pack.UseTemporal();
+ ConventionRegistry.Register("ConventionPack", pack, t => true);
+ }
+
+ private class TestClass
+ {
+ public DateOnly Property { get; set; }
+ }
+
+ [Test]
+ public void ShouldDeserialize()
+ {
+ string json = @"{""Property"" : ""2022-04-01""}";
+ TestClass result = BsonSerializer.Deserialize(json);
+
+ result.Should().NotBeNull();
+ result.Property.Should().Be(new DateOnly(2022, 4, 1));
+ }
+
+ [Test]
+ public void ShouldSerialize()
+ {
+ TestClass obj = new TestClass
+ {
+ Property = new DateOnly(2022, 4, 1),
+ };
+
+ string json = obj.ToJson(new JsonWriterSettings
+ {
+ Indent = true
+ });
+
+ Console.WriteLine(json);
+ json.Should().Contain(@"""2022-04-01""");
+ }
+ }
+}
diff --git a/tests/Fluxera.Temporal.MongoDB.UnitTests/Fluxera.Temporal.MongoDB.UnitTests.csproj b/tests/Fluxera.Temporal.MongoDB.UnitTests/Fluxera.Temporal.MongoDB.UnitTests.csproj
new file mode 100644
index 0000000..21769b2
--- /dev/null
+++ b/tests/Fluxera.Temporal.MongoDB.UnitTests/Fluxera.Temporal.MongoDB.UnitTests.csproj
@@ -0,0 +1,26 @@
+
+
+
+ net6.0
+ enable
+
+ false
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
diff --git a/tests/Fluxera.Temporal.MongoDB.UnitTests/TestsBase.cs b/tests/Fluxera.Temporal.MongoDB.UnitTests/TestsBase.cs
new file mode 100644
index 0000000..6d2b341
--- /dev/null
+++ b/tests/Fluxera.Temporal.MongoDB.UnitTests/TestsBase.cs
@@ -0,0 +1,12 @@
+namespace Fluxera.Temporal.MongoDB.UnitTests
+{
+ using System.Text.RegularExpressions;
+
+ public abstract class TestsBase
+ {
+ protected string Minify(string json)
+ {
+ return Regex.Replace(json, @"(""(?:[^""\\]|\\.)*"")|\s+", "$1", RegexOptions.Compiled);
+ }
+ }
+}
diff --git a/tests/Fluxera.Temporal.MongoDB.UnitTests/TimeOnlyTests.cs b/tests/Fluxera.Temporal.MongoDB.UnitTests/TimeOnlyTests.cs
new file mode 100644
index 0000000..e123332
--- /dev/null
+++ b/tests/Fluxera.Temporal.MongoDB.UnitTests/TimeOnlyTests.cs
@@ -0,0 +1,54 @@
+namespace Fluxera.Temporal.MongoDB.UnitTests
+{
+ using System;
+ using FluentAssertions;
+ using global::MongoDB.Bson;
+ using global::MongoDB.Bson.IO;
+ using global::MongoDB.Bson.Serialization;
+ using global::MongoDB.Bson.Serialization.Conventions;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class TimeOnlyTests : TestsBase
+ {
+ [SetUp]
+ public void SetUp()
+ {
+ ConventionPack pack = new ConventionPack();
+ pack.UseTemporal();
+ ConventionRegistry.Register("ConventionPack", pack, t => true);
+ }
+
+ private class TestClass
+ {
+ public TimeOnly Property { get; set; }
+ }
+
+ [Test]
+ public void ShouldDeserialize()
+ {
+ string json = @"{""Property"" : ""10:45:35.8471835""}";
+ TestClass result = BsonSerializer.Deserialize(json);
+
+ result.Should().NotBeNull();
+ result.Property.Should().Be(TimeOnly.Parse("10:45:35.8471835"));
+ }
+
+ [Test]
+ public void ShouldSerialize()
+ {
+ TestClass obj = new TestClass
+ {
+ Property = TimeOnly.Parse("10:45:35.8471835")
+ };
+
+ string json = obj.ToJson(new JsonWriterSettings
+ {
+ Indent = true
+ });
+
+ Console.WriteLine(json);
+ json.Should().Contain(@"""10:45:35.8471835""");
+ }
+ }
+}