Moh Tarvirdi
Moh Tarvirdi

Reputation: 705

NLog use Persian Calendar Date format

I am interested in using NLog in my C# project and found it great, but
In my country Clients works with "Persian Calendar".
As you know Microsoft developed a library to support named "C# Persian Calendar class".
I need Persian calendar date format in two places
1-Message Time stamp
2-Date based File Name
How to force NLog to use " C# Persian Calendar class" in above usages?
Thanks

Upvotes: 2

Views: 536

Answers (2)

wageoghe
wageoghe

Reputation: 27618

You don't necessarily have to modify NLog source and build it yourself. You could probably write your own PersianDateLayoutRenderer. It is then a simple matter of configuring NLog to use your layout renderer rather than the one of NLog's built in layout renderers. When you upgrade to a new version NLog, your layout renderer should still work.

Here is an example that combines NLog's LongDateLayoutRenderer and the .NET Persian Calendar. I don't know if formatting is available for Persian dates, so I just hardcoded a format.

You can configure this in the NLog.config file by using ${persianlongdate} rather than ${shortdate}, ${longdate}, or ${date}.

I haven't tried to build or run this, but it should be pretty close. You could easily modify it to use Jon's Noda Time if you decide to try that route.

You can find the source for NLog's LongDateLayoutRenderer (and DateLayoutRenderer and ShortDateLayoutRenderer) here:

https://github.com/NLog/NLog/blob/master/src/NLog/LayoutRenderers

namespace MyLayoutRenderers
{
    using System.ComponentModel;
    using System.Globalization;
    using System.Text;

    using NLog.Config;

    [LayoutRenderer("persianlongdate")]
    [ThreadAgnostic]
    public class PersianSLongDateLayoutRenderer : LayoutRenderer
    {
        PersianCalendar pc = new PersianCalendar();

        /// <summary>
        /// Gets or sets a value indicating whether to output UTC time instead of local time.
        /// </summary>
        /// <docgen category='Rendering Options' order='10' />
        [DefaultValue(false)]
        public bool UniversalTime { get; set; }

        /// <summary>
        /// Renders the current short date string (yyyy-MM-dd) and appends it to the specified <see cref="StringBuilder" />.
        /// </summary>
        /// <param name="builder">The <see cref="StringBuilder"/> to append the rendered data to.</param>
        /// <param name="logEvent">Logging event.</param>
        protected override void Append(StringBuilder builder, LogEventInfo logEvent)
        {
            DateTime ts = logEvent.TimeStamp;

            //Not sure if UniversalTime makes sense for PersianCalendar.  Do you?
            if (this.UniversalTime)
            {
                ts = ts.ToUniversalTime();
            }

            builder.Append(String.Format("{0}-{1}-{2}-{3}:{4}-{5}-{6}",
                pc.GetDayOfWeek(ts),
                pc.GetMonth(ts),
                pc.GetDayOfMonth(ts),
                pc.GetYear(ts),
                pc.GetHour(ts), 
                pc.GetMinute(ts),
                pc.GetSecond(ts));
        }
    }
}

Good luck!

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1502835

There are two difficulties with this:

  • You'd need to work out how the formatting is performed in both of these cases, and see how you can customize it, e.g. by specifying a different culture or a formatting delegate
  • The Persian calendar isn't currently an optional calendar for any culture, so using DateTime.ToString won't work anyway :(

You'll definitely need to look into the source code (or at least documentation) for NLog to find out whether there's a way of configuring the formatting. Once you've worked out how to get your own code to be executed there - e.g. by writing your own subclass, potentially - you'll need to work out how to do the actualy formatting.

You could do this using the BCL, calling into PersianCalendar and doing simple numeric formatting. Or you could use my Noda Time library, which also has Persian calendar support (as of Noda Time 1.3). You'd want something like:

var gregorian = new LocalDate(2014, 11, 6); // Or whatever
var persian = gregorian.WithCalendar(CalendarSystem.GetPersianCalendar());
var text = persian.ToString("yyyy-MM-dd"); // Or create a LocalDatePattern

Upvotes: 2

Related Questions