Skip to content

Commit e9c53a7

Browse files
committed
TimestampTokenRenderer simplified and UtcTimestamp support fixed for standard formating
- keep render performance in mind / i.e. keep optimizations from #134 - ensure UtcTimestamp without format string is rendered without " +00:00" suffix by rendering as DateTime (same behavior as Serilog's MessageTemplateTextFormatter) Relates to #164
1 parent 4c0dc6f commit e9c53a7

File tree

1 file changed

+43
-26
lines changed

1 file changed

+43
-26
lines changed

src/Serilog.Sinks.Console/Sinks/SystemConsole/Output/TimestampTokenRenderer.cs

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,68 +26,85 @@ class TimestampTokenRenderer : OutputTemplateTokenRenderer
2626
{
2727
readonly ConsoleTheme _theme;
2828
readonly PropertyToken _token;
29+
readonly string? _format;
2930
readonly IFormatProvider? _formatProvider;
3031
readonly bool _convertToUtc;
3132

3233
public TimestampTokenRenderer(ConsoleTheme theme, PropertyToken token, IFormatProvider? formatProvider, bool convertToUtc)
3334
{
3435
_theme = theme;
3536
_token = token;
37+
_format = token.Format;
3638
_formatProvider = formatProvider;
3739
_convertToUtc = convertToUtc;
3840
}
3941

4042
public override void Render(LogEvent logEvent, TextWriter output)
4143
{
42-
var timestamp = _convertToUtc
43-
? logEvent.Timestamp.ToUniversalTime()
44-
: logEvent.Timestamp;
45-
var sv = new DateTimeOffsetValue(timestamp);
46-
4744
var _ = 0;
4845
using (_theme.Apply(output, ConsoleThemeStyle.SecondaryText, ref _))
4946
{
5047
if (_token.Alignment is null)
5148
{
52-
sv.Render(output, _token.Format, _formatProvider);
49+
Render(output, logEvent.Timestamp);
5350
}
5451
else
5552
{
5653
var buffer = new StringWriter();
57-
sv.Render(buffer, _token.Format, _formatProvider);
54+
Render(buffer, logEvent.Timestamp);
5855
var str = buffer.ToString();
5956
Padding.Apply(output, str, _token.Alignment);
6057
}
6158
}
6259
}
6360

64-
readonly struct DateTimeOffsetValue
61+
private void Render(TextWriter output, DateTimeOffset timestamp)
6562
{
66-
public DateTimeOffsetValue(DateTimeOffset value)
63+
// When a DateTimeOffset is converted to a string, the default format automatically adds the "+00:00" explicit offset to the output string.
64+
// As the TimestampTokenRenderer is also used for rendering the UtcTimestamp which is always in UTC by definition, the +00:00 suffix should be avoided.
65+
// This is done using the same approach as Serilog's MessageTemplateTextFormatter. In case output should be converted to UTC, in order to avoid a zone specifier,
66+
// the DateTimeOffset is converted to a DateTime which then renders as expected.
67+
68+
var custom = (ICustomFormatter?)_formatProvider?.GetFormat(typeof(ICustomFormatter));
69+
if (custom != null)
6770
{
68-
Value = value;
71+
output.Write(custom.Format(_format, _convertToUtc ? timestamp.UtcDateTime : timestamp, _formatProvider));
72+
return;
6973
}
7074

71-
public DateTimeOffset Value { get; }
72-
73-
public void Render(TextWriter output, string? format = null, IFormatProvider? formatProvider = null)
75+
if (_convertToUtc)
7476
{
75-
var custom = (ICustomFormatter?)formatProvider?.GetFormat(typeof(ICustomFormatter));
76-
if (custom != null)
77-
{
78-
output.Write(custom.Format(format, Value, formatProvider));
79-
return;
80-
}
77+
RenderDateTime(output, timestamp.UtcDateTime);
78+
}
79+
else
80+
{
81+
RenderDateTimeOffset(output, timestamp);
82+
}
83+
}
8184

85+
private void RenderDateTimeOffset(TextWriter output, DateTimeOffset timestamp)
86+
{
8287
#if FEATURE_SPAN
83-
Span<char> buffer = stackalloc char[32];
84-
if (Value.TryFormat(buffer, out int written, format, formatProvider ?? CultureInfo.InvariantCulture))
85-
output.Write(buffer.Slice(0, written));
86-
else
87-
output.Write(Value.ToString(format, formatProvider ?? CultureInfo.InvariantCulture));
88+
Span<char> buffer = stackalloc char[32];
89+
if (timestamp.TryFormat(buffer, out int written, _format, _formatProvider ?? CultureInfo.InvariantCulture))
90+
output.Write(buffer.Slice(0, written));
91+
else
92+
output.Write(timestamp.ToString(_format, _formatProvider ?? CultureInfo.InvariantCulture));
8893
#else
89-
output.Write(Value.ToString(format, formatProvider ?? CultureInfo.InvariantCulture));
94+
output.Write(timestamp.ToString(_format, _formatProvider ?? CultureInfo.InvariantCulture));
95+
#endif
96+
}
97+
98+
private void RenderDateTime(TextWriter output, DateTime utcTimestamp)
99+
{
100+
#if FEATURE_SPAN
101+
Span<char> buffer = stackalloc char[32];
102+
if (utcTimestamp.TryFormat(buffer, out int written, _format, _formatProvider ?? CultureInfo.InvariantCulture))
103+
output.Write(buffer.Slice(0, written));
104+
else
105+
output.Write(utcTimestamp.ToString(_format, _formatProvider ?? CultureInfo.InvariantCulture));
106+
#else
107+
output.Write(utcTimestamp.ToString(_format, _formatProvider ?? CultureInfo.InvariantCulture));
90108
#endif
91-
}
92109
}
93110
}

0 commit comments

Comments
 (0)