Visitar URL original
Add `DateTimeOffset` raw-value support to `${date}` / `${longdate}` (or add a new `${datetimeoffset}` renderer) · Issue #6161 · NLog/NLog · GitHub
Skip to content

Add DateTimeOffset raw-value support to ${date} / ${longdate} (or add a new ${datetimeoffset} renderer) #6161

Closed
LorneCash/NLog
#1

Description

@LorneCash

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:

  1. Manually populate an event property in every log call (or via a wrapper):

    e.Properties["Timestamp"] = new DateTimeOffset(e.TimeStamp);
  2. 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 IRawValue plumbing — no new abstraction needed.
  • It keeps file/console targets working (string rendering is unchanged) while enabling SQL DATETIMEOFFSET columns to receive a native typed value.
  • It removes the only remaining reason to push timestamps through Properties, which is a documented pain point for SQL DatabaseTarget users.

Alternatives considered

Environment

  • NLog: 6.1.2
  • NLog.Database: 6.0.3
  • Target: SQL Server DATETIMEOFFSET column via Microsoft.Data.SqlClient

Activity

  1. snakefoot commented on Apr 21, 2026

    @snakefoot
    Contributor

    NLog v6.1.2 added support for converting DateTime to DateTimeOffset as part of #6116

    if (typeCode == TypeCode.DateTime && typeof(DateTimeOffset) == propertyType)
       return new DateTimeOffset(convertibleValue.ToDateTime(formatProvider));

    And also verified here: NLog/NLog.Targets.Database#66 using ${date} with DbType.DateTimeOffset

    DateTime 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).

  2. snakefoot commented on Apr 23, 2026

    @snakefoot
    Contributor

    Closing the issue as it seems resolved by NLog v6.1.2 - #6162 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions