带有自定义IFormatProvider的DateTime.ToString()中的第一个月份

时间:2015-04-17 20:19:00

标签: c# datetime string-formatting tostring

DateTime格式字符串中是否有一种方法只包含该月的第一个字母?

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"

如果没有,是否有某种方法可以向系统范围的IFormatProvider添加新的自定义格式来处理此问题?

请注意“你为什么要这样做?” people:这是供应商的图表控件,只接受格式字符串。我们正在努力使这些日期尽可能短,并且它们适用于国际用户,因此本月的数字将无效。我无法传递新的IFormatProvider,因此我必须以某种方式修改现有的IFormatProvider (希望不会破坏它)。

3 个答案:

答案 0 :(得分:4)

让我们深入了解DateTime.ToString()实现。如果没有IFormatProvider对象传递给它,它将使用System.Globalization.DateTimeFormatInfo.CurrentInfo作为DateTimeFormatInfo对象来获取有关如何构建字符串表示的信息。反过来,CurrentInfoThread.CurrentThread.CurrentCulture获取。

因此,您希望以某种方式设置当前线程文化,它具有一个字符月份名称(或缩写,如下例所示),然后使用常规格式字符串。实现这一目标的一种方法如下:

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"));
        }
    }
}

答案 1 :(得分:3)

以下是使用自定义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;
            }
        }
    }

你可以像这样使用它:

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

如果无法将FormatProvider传递给您想要的方法,那么这是一种令人讨厌的方法,请谨慎使用!

    var currentCulture = Thread.CurrentThread.CurrentCulture.Clone() as CultureInfo;
    currentCulture.DateTimeFormat = SingleLetterMonthNameFormatter.FormatProvider as DateTimeFormatInfo;
    Thread.CurrentThread.CurrentCulture = currentCulture;
    Console.WriteLine(DateTime.Now.ToString("MMM"));

答案 2 :(得分:-1)

(new DateTime(2015,1,12).ToString("MM")[0])+(new DateTime(2015,1,12).ToString("-dd-yy"))

但要注意与第一个字母相同的月份(1月对7月),根据其他文化的不同,可能会更好或更差。