Repository navigation
Description
Background
Issue #6115 / PR #6116 added typed DateTimeOffset flow through DatabaseTarget when DatabaseParameterInfo.ParameterType = typeof(DateTimeOffset) and the layout's raw value is already a DateTimeOffset object.
That fix works great when the user populates LogEventInfo.Properties["Timestamp"] = new DateTimeOffset(e.TimeStamp) and uses ${event-properties:item=Timestamp} as the layout — the typed object flows through to the SqlParameter without a string round-trip.
Problem
LogEventInfo.TimeStamp is a DateTime, and ${date} / ${longdate} only expose it as a DateTime raw value. To target a SQL DATETIMEOFFSET column from e.TimeStamp, callers must:
-
Manually populate an event property in every log call (or via a wrapper):
e.Properties["Timestamp"] = new DateTimeOffset(e.TimeStamp);
-
Reference it via
${event-properties:item=Timestamp}instead of the built-in${date}.
This is boilerplate that exists solely to bridge DateTime → DateTimeOffset for the typed parameter pipeline. Using ${date:format=o} defeats the raw-value path (forces string rendering), and relying on ParameterType = typeof(DateTimeOffset) to convert from a DateTime raw value loses fidelity for users whose TimeSource is configured for a specific kind.
Proposed Enhancement
Either of the following would eliminate the workaround:
Option A (preferred — minimal surface area)
Add an asDateTimeOffset (bool) property to DateLayoutRenderer (and LongDateLayoutRenderer). When true, the renderer's IRawValue.TryGetRawValue returns a DateTimeOffset constructed from LogEventInfo.TimeStamp (using TimeZoneInfo.Local for Kind.Local / Kind.Unspecified and TimeSpan.Zero for Kind.Utc). String rendering remains unchanged.
<parameter name="@Timestamp"
layout="${date:asDateTimeOffset=true}"
parameterType="System.DateTimeOffset" />Option B (purely additive)
Add a dedicated ${datetimeoffset} layout renderer that always exposes e.TimeStamp as a typed DateTimeOffset raw value, with an optional format for string rendering.
Why this fits NLog's model
- It follows the same pattern PR PropertyTypeConverter - Prioritize IFormattable ToString when Format specified #6116 established: typed values flow end-to-end without string round-trips.
- It uses the existing
IRawValueplumbing — no new abstraction needed. - It keeps file/console targets working (string rendering is unchanged) while enabling SQL
DATETIMEOFFSETcolumns to receive a native typed value. - It removes the only remaining reason to push timestamps through
Properties, which is a documented pain point for SQLDatabaseTargetusers.
Alternatives considered
- Setting
e.Properties["Timestamp"] = new DateTimeOffset(e.TimeStamp)— works today but is per-call boilerplate. ${date:format=o}+ParameterType=DateTimeOffset— round-trips through string, defeats the benefit of PropertyTypeConverter - Prioritize IFormattable ToString when Format specified #6116.- Custom
LayoutRenderersubclass — every consumer would have to ship one; better suited as a built-in.
Environment
- NLog: 6.1.2
- NLog.Database: 6.0.3
- Target: SQL Server
DATETIMEOFFSETcolumn viaMicrosoft.Data.SqlClient
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Activity
snakefoot commentedon Apr 21, 2026
NLog v6.1.2 added support for converting DateTime to DateTimeOffset as part of #6116
And also verified here: NLog/NLog.Targets.Database#66 using
${date}withDbType.DateTimeOffsetDateTime uses a single-bit to specify Local- / Utc-time, and I guess DateTimeOffset-constructor inspects this when converting. If improvements can be made to the conversion
new DateTimeOffset(convertibleValue.ToDateTime(formatProvider))then please tell (or create pull-request with code-suggestion or unit-test).snakefoot commentedon Apr 23, 2026
Closing the issue as it seems resolved by NLog v6.1.2 - #6162 (comment)