Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

First letter of month in DateTime.ToString() with custom IFormatProvider

Is there a way in DateTime format strings to have include just the first letter of the month?

new DateTime(2015, 1, 12).ToString("M-dd-yy") // "1-12-15",  but I want "J-02-15"
new DateTime(2000, 11, 7).ToString("M-dd-yy") // "11-07-00", but I want "N-17-00"

If not, is there some way to add a new, custom format to the system-wide IFormatProvider to handle this?

Note for the "why are you trying to do it that way?" people: This is for a vendor's chart control, which only accepts a format string. We are trying to make these dates as short as possible, and they are for international users, so numbers for the month won't work. I can't pass in a new IFormatProvider, so I would have to somehow modify the existing IFormatProvider (hopefully without breaking it).

like image 696
snumpy Avatar asked Apr 17 '15 20:04

snumpy


People also ask

How do I change the date format in ToString?

To do this, you use the "MM/yyyy" format string. The format string uses the current culture's date separator. Getting a string that contains the date and time in a specific format. For example, the "MM/dd/yyyyHH:mm" format string displays the date and time string in a fixed format such as "19//03//2013 18:06".

What is TT time format?

Terrestrial Time (TT) is a modern astronomical time standard defined by the International Astronomical Union, primarily for time-measurements of astronomical observations made from the surface of Earth.

How do I change the format of a DateTime object in Python?

Use datetime. strftime(format) to convert a datetime object into a string as per the corresponding format . The format codes are standard directives for mentioning in which format you want to represent datetime. For example, the %d-%m-%Y %H:%M:%S codes convert date to dd-mm-yyyy hh:mm:ss format.

What is timestamp FFF?

The "fff" custom format specifier represents the three most significant digits of the seconds fraction; that is, it represents the milliseconds in a date and time value.


2 Answers

Let's dig a bit into DateTime.ToString() implementation. When no IFormatProvider object is passed to it, it will use System.Globalization.DateTimeFormatInfo.CurrentInfo as the DateTimeFormatInfo object to get information on how to build string representation. CurrentInfo, in turn, gets it from Thread.CurrentThread.CurrentCulture.

So you'd want to set up current thread culture in a way, that it has one character month names (or abbreviations as in example below), then use regular format string. One way to achieve this is the following:

using System;
using System.Globalization;
using System.Threading;

namespace DTFTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var dt = DateTime.Now;
            Thread.CurrentThread.CurrentCulture = new CultureInfo("EN-US", true);
            var ci = Thread.CurrentThread.CurrentCulture;
            var monthNames = new[] { "J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D", string.Empty };
            ci.DateTimeFormat.AbbreviatedMonthNames = monthNames;
            Console.WriteLine(dt.ToString("MMM-dd-yyyy"));
        }
    }
}
like image 86
n0rd Avatar answered Oct 07 '22 13:10

n0rd


Here's a solution using a customized FormatProvider:

    public static class SingleLetterMonthNameFormatter
    {
        private static IFormatProvider _formatProvider;
        public static IFormatProvider FormatProvider
        {
            get
            {
                if (_formatProvider == null)
                {
                    var dtfi = new DateTimeFormatInfo();
                    dtfi.AbbreviatedMonthNames = dtfi.MonthNames.Select(x => x.FirstOrDefault().ToString()).ToArray();
                    _formatProvider = dtfi;
                }
                return _formatProvider;
            }
        }
    }

You can use it like this:

var monthName = DateTime.Now.ToString("MMM", SingleLetterMonthNameFormatter.FormatProvider) //First letter of month name

If there's no way to pass a FormatProvider to the method you want, there's a nasty way to do it, use with care!

    var currentCulture = Thread.CurrentThread.CurrentCulture.Clone() as CultureInfo;
    currentCulture.DateTimeFormat = SingleLetterMonthNameFormatter.FormatProvider as DateTimeFormatInfo;
    Thread.CurrentThread.CurrentCulture = currentCulture;
    Console.WriteLine(DateTime.Now.ToString("MMM"));
like image 36
brz Avatar answered Oct 07 '22 13:10

brz