diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 47cb950ce..35a7da52a 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -40,6 +40,7 @@ END TEMPLATE--> ### New features * You can use `Subs.CVar()` from an entity systems to subscribe to CVar changes. This is more convenient than `IConfigurationManager.OnValueChanged` as it automatically unsubscribes on system shutdown. +* There is now a built-in type serializer for `DateTime`, so you can put `DateTime`s in your data fields. ### Bugfixes diff --git a/Robust.Shared/Serialization/TypeSerializers/Implementations/DateTimeSerializer.cs b/Robust.Shared/Serialization/TypeSerializers/Implementations/DateTimeSerializer.cs new file mode 100644 index 000000000..7f62cf2b9 --- /dev/null +++ b/Robust.Shared/Serialization/TypeSerializers/Implementations/DateTimeSerializer.cs @@ -0,0 +1,65 @@ +using System; +using System.Globalization; +using JetBrains.Annotations; +using Robust.Shared.IoC; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Serialization.Markdown; +using Robust.Shared.Serialization.Markdown.Validation; +using Robust.Shared.Serialization.Markdown.Value; +using Robust.Shared.Serialization.TypeSerializers.Interfaces; + +namespace Robust.Shared.Serialization.TypeSerializers.Implementations; + +/// +/// Implements serialization for . +/// +/// +/// Serialization is implemented with and the "o" format specifier. +/// +[TypeSerializer] +public sealed class DateTimeSerializer : ITypeSerializer, ITypeCopyCreator +{ + public ValidationNode Validate( + ISerializationManager serializationManager, + ValueDataNode node, + IDependencyCollection dependencies, + ISerializationContext? context = null) + { + return DateTime.TryParse(node.Value, null, DateTimeStyles.RoundtripKind, out _) + ? new ValidatedValueNode(node) + : new ErrorNode(node, "Failed parsing DateTime"); + } + + public DateTime Read( + ISerializationManager serializationManager, + ValueDataNode node, + IDependencyCollection dependencies, + SerializationHookContext hookCtx, + ISerializationContext? context = null, + ISerializationManager.InstantiationDelegate? instanceProvider = null) + { + return DateTime.Parse(node.Value, null, DateTimeStyles.RoundtripKind); + } + + public DataNode Write( + ISerializationManager serializationManager, + DateTime value, + IDependencyCollection dependencies, + bool alwaysWrite = false, + ISerializationContext? context = null) + { + return new ValueDataNode(value.ToString("o")); + } + + [MustUseReturnValue] + public DateTime CreateCopy( + ISerializationManager serializationManager, + DateTime source, + IDependencyCollection dependencies, + SerializationHookContext hookCtx, + ISerializationContext? context = null) + { + return source; + } +} diff --git a/Robust.UnitTesting/Shared/Serialization/TypeSerializers/DateTimeSerializerTest.cs b/Robust.UnitTesting/Shared/Serialization/TypeSerializers/DateTimeSerializerTest.cs new file mode 100644 index 000000000..39853217f --- /dev/null +++ b/Robust.UnitTesting/Shared/Serialization/TypeSerializers/DateTimeSerializerTest.cs @@ -0,0 +1,31 @@ +using System; +using System.Globalization; +using NUnit.Framework; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Serialization.Markdown.Value; +using Robust.Shared.Serialization.TypeSerializers.Implementations; + +namespace Robust.UnitTesting.Shared.Serialization.TypeSerializers; + +[TestFixture] +[TestOf(typeof(DateTimeSerializer))] +internal sealed class DateTimeSerializerTest : SerializationTest +{ + [Test] + public void WriteTest() + { + var dateTime = DateTime.UtcNow; + var result = Serialization.WriteValueAs(dateTime); + + var parsed = DateTime.Parse(result.Value, null, DateTimeStyles.RoundtripKind); + Assert.That(parsed, Is.EqualTo(dateTime)); + } + + [Test] + public void ReadTest() + { + var result = Serialization.Read(new ValueDataNode("2020-07-10 15:00:00.000")); + + Assert.That(result, Is.EqualTo(new DateTime(2020, 07, 10, 15, 0, 0))); + } +}