Skip to content

Commit

Permalink
DateOnly and TimeOnly support (#1702)
Browse files Browse the repository at this point in the history
* .

* .

* Update global.json

* FEATURE_DATE_AND_TIME_ONLY

* Update PropertyValueConverter.cs

Co-authored-by: Nicholas Blumhardt <nblumhardt@nblumhardt.com>
  • Loading branch information
SimonCropp and nblumhardt committed Jul 26, 2022
1 parent f986e62 commit 921037a
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 3 deletions.
1 change: 1 addition & 0 deletions Serilog.sln.DotSettings
Expand Up @@ -195,6 +195,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/VBNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/VBNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/VBNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EdotCover_002EIde_002ECore_002EFilterManagement_002EModel_002ESolutionFilterSettingsManagerMigrateSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpFileLayoutPatternsUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
Expand Down
5 changes: 4 additions & 1 deletion src/Serilog/Capturing/PropertyValueConverter.cs
Expand Up @@ -42,7 +42,10 @@ partial class PropertyValueConverter : ILogEventPropertyFactory, ILogEventProper
typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal),
typeof(string),
typeof(DateTime), typeof(DateTimeOffset), typeof(TimeSpan),
typeof(Guid), typeof(Uri)
typeof(Guid), typeof(Uri),
#if FEATURE_DATE_AND_TIME_ONLY
typeof(TimeOnly), typeof(DateOnly)
#endif
};

readonly IDestructuringPolicy[] _destructuringPolicies;
Expand Down
22 changes: 22 additions & 0 deletions src/Serilog/Formatting/Json/JsonFormatter.cs
Expand Up @@ -103,6 +103,10 @@ public class JsonFormatter : ITextFormatter
{ typeof(string), (v, _, w) => WriteString((string)v, w) },
{ typeof(DateTime), (v, _, w) => WriteDateTime((DateTime)v, w) },
{ typeof(DateTimeOffset), (v, _, w) => WriteOffset((DateTimeOffset)v, w) },
#if FEATURE_DATE_AND_TIME_ONLY
{ typeof(DateOnly), (v, _, w) => WriteDateOnly((DateOnly)v, w) },
{ typeof(TimeOnly), (v, _, w) => WriteTimeOnly((TimeOnly)v, w) },
#endif
{ typeof(ScalarValue), (v, q, w) => WriteLiteral(((ScalarValue)v).Value, w, q) },
{ typeof(SequenceValue), (v, _, w) => WriteSequence(((SequenceValue)v).Elements, w) },
{ typeof(DictionaryValue), (v, _, w) => WriteDictionary(((DictionaryValue)v).Elements, w) },
Expand Down Expand Up @@ -429,6 +433,24 @@ static void WriteDateTime(DateTime value, TextWriter output)
output.Write("\"");
}

#if FEATURE_DATE_AND_TIME_ONLY

static void WriteDateOnly(DateOnly value, TextWriter output)
{
output.Write("\"");
output.Write(value.ToString("yyyy-MM-dd"));
output.Write("\"");
}

static void WriteTimeOnly(TimeOnly value, TextWriter output)
{
output.Write("\"");
output.Write(value.ToString("O"));
output.Write("\"");
}

#endif

static void WriteString(string value, TextWriter output)
{
JsonValueFormatter.WriteQuotedJsonString(value, output);
Expand Down
32 changes: 32 additions & 0 deletions src/Serilog/Formatting/Json/JsonValueFormatter.cs
Expand Up @@ -219,6 +219,20 @@ protected virtual void FormatLiteralValue(object value, TextWriter output)
FormatTimeSpanValue(timeSpan, output);
return;
}

#if FEATURE_DATE_AND_TIME_ONLY
if (value is DateOnly dateOnly)
{
FormatDateOnlyValue(dateOnly, output);
return;
}

if (value is TimeOnly timeOnly)
{
FormatTimeOnlyValue(timeOnly, output);
return;
}
#endif
}

FormatLiteralObjectValue(value, output);
Expand Down Expand Up @@ -270,6 +284,24 @@ static void FormatTimeSpanValue(TimeSpan value, TextWriter output)
output.Write('\"');
}

#if FEATURE_DATE_AND_TIME_ONLY

static void FormatDateOnlyValue(DateOnly value, TextWriter output)
{
output.Write('\"');
output.Write(value.ToString("yyyy-MM-dd"));
output.Write('\"');
}

static void FormatTimeOnlyValue(TimeOnly value, TextWriter output)
{
output.Write('\"');
output.Write(value.ToString("O"));
output.Write('\"');
}

#endif

static void FormatLiteralObjectValue(object value, TextWriter output)
{
if (value == null) throw new ArgumentNullException(nameof(value));
Expand Down
2 changes: 1 addition & 1 deletion src/Serilog/Serilog.csproj
Expand Up @@ -46,7 +46,7 @@
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net6.0' ">
<DefineConstants>$(DefineConstants);ASYNCLOCAL;HASHTABLE;FEATURE_DEFAULT_INTERFACE;FEATURE_SPAN</DefineConstants>
<DefineConstants>$(DefineConstants);ASYNCLOCAL;HASHTABLE;FEATURE_DEFAULT_INTERFACE;FEATURE_SPAN;FEATURE_DATE_AND_TIME_ONLY</DefineConstants>
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
Expand Down
36 changes: 36 additions & 0 deletions test/Serilog.Tests/Formatting/Json/JsonFormatterTests.cs
Expand Up @@ -31,6 +31,42 @@ public void JsonFormattedEventsIncludeTimestamp()
(string)formatted.Timestamp);
}

#if FEATURE_DATE_AND_TIME_ONLY

[Fact]
public void JsonFormattedDateOnly()
{
var @event = new LogEvent(
DateTimeOffset.MaxValue,
LogEventLevel.Information,
null,
Some.MessageTemplate(),
new[] {new LogEventProperty("name", new ScalarValue(DateOnly.MaxValue))});

var formatted = FormatJson(@event);
Assert.Equal(
"9999-12-31",
(string) formatted.Properties.name);
}

[Fact]
public void JsonFormattedTimeOnly()
{
var @event = new LogEvent(
DateTimeOffset.MaxValue,
LogEventLevel.Information,
null,
Some.MessageTemplate(),
new[] {new LogEventProperty("name", new ScalarValue(TimeOnly.MaxValue))});

var formatted = FormatJson(@event);
Assert.Equal(
"23:59:59.9999999",
(string) formatted.Properties.name);
}

#endif

static string FormatToJson(LogEvent @event)
{
var formatter = new JsonFormatter();
Expand Down
16 changes: 16 additions & 0 deletions test/Serilog.Tests/Formatting/Json/JsonValueFormatterTests.cs
Expand Up @@ -51,6 +51,22 @@ public void DateTimesFormatAsIso8601()
JsonLiteralTypesAreFormatted(new DateTime(2016, 01, 01, 13, 13, 13, DateTimeKind.Utc), "\"2016-01-01T13:13:13.0000000Z\"");
}

#if FEATURE_DATE_AND_TIME_ONLY

[Fact]
public void DateOnly()
{
JsonLiteralTypesAreFormatted(new DateOnly(2016, 01, 01), "\"2016-01-01\"");
}

[Fact]
public void TimeOnly()
{
JsonLiteralTypesAreFormatted(new TimeOnly(13, 01, 01, 999), "\"13:01:01.9990000\"");
}

#endif

[Fact]
public void DoubleFormatsAsNumber()
{
Expand Down
2 changes: 1 addition & 1 deletion test/Serilog.Tests/Serilog.Tests.csproj
Expand Up @@ -40,6 +40,6 @@
<DefineConstants>$(DefineConstants);ASYNCLOCAL;FEATURE_DEFAULT_INTERFACE;FEATURE_SPAN</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net6.0' ">
<DefineConstants>$(DefineConstants);ASYNCLOCAL;FEATURE_DEFAULT_INTERFACE;FEATURE_SPAN</DefineConstants>
<DefineConstants>$(DefineConstants);ASYNCLOCAL;FEATURE_DEFAULT_INTERFACE;FEATURE_SPAN;FEATURE_DATE_AND_TIME_ONLY</DefineConstants>
</PropertyGroup>
</Project>

0 comments on commit 921037a

Please sign in to comment.