Я пытаюсь прочитать номер месяца из короткого месяца (вот так) DateTime.ToString("МММ")
Итак, прочитайте «февраль» или «март» и верните 2 или 3.
Это функция, которую я придумал, однако мне интересно, могу ли я что-то сделать с точным парсе и передать фиктивный год/день, чтобы получить из этого номер месяца?
private int GetNumberFromShortMonth(string month)
{
var monthNo = -1;
var dt = new DateTime(2000, 01, 01);
for (int i = 0; i <= 11; i++)
{
dt = dt.AddMonths(i);
if (string.Equals(dt.ToString("MMM"), month, StringComparison.OrdinalIgnoreCase))
{
monthNo = dt.Month;
break;
}
}
return monthNo;
}
Вместо этого я бы предложил использовать DateTimeFormatInfo.AbbreviatedMonthNames. (Найдите индекс внутри него, без учета регистра.)
Переключить регистр или словарь? Если это должно работать только с одной культурой
@JonSkeet — DateTimeFormatInfo.CurrentInfo.AbbreviatedMonthNames
возвращает 13 предметов. Месяцы плюс пустая строка. Почему это?
var result = Array.IndexOf(CultureInfo.CurrentCulture.DateTimeFormat.AbbreviatedMonthNames, month) + 1;
@Enigmativity: Я подозреваю, что это сделано для единообразия, поэтому он всегда может возвращать названия 13 месяцев (для календарей с 13 месяцами, например, еврейского календаря в високосный год).
Я бы также рекомендовал вам учитывать, что в других языках для названий месяцев не используются одни и те же строки, поэтому будьте осторожны.
private static int GetNumberFromShortMonth(string month)
{
if (DateTime.TryParseExact(month, "MMM", null, System.Globalization.DateTimeStyles.None, out DateTime dt))
{
return dt.Month;
}
return -1;
}
Один из способов сделать это — использовать DateTimeFormatInfo.InvariantInfo.AbbreviatedMonthNames
, который возвращает следующий массив значений.
["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""]
using System.Globalization;
namespace MyProgram;
public class Program
{
public static void Main()
{
const int NotFound = -1;
Console.WriteLine($"Jan: {GetNumberFromShortMonth("JAN")}");
Console.WriteLine($"Feb: {GetNumberFromShortMonth("Feb")}");
Console.WriteLine($"Mar: {GetNumberFromShortMonth("mar")}");
Console.WriteLine($"Apr: {GetNumberFromShortMonth("APR")}");
Console.WriteLine($"May: {GetNumberFromShortMonth("May")}");
Console.WriteLine($"Jun: {GetNumberFromShortMonth("juN")}");
Console.WriteLine($"Jul: {GetNumberFromShortMonth("JUL")}");
Console.WriteLine($"Aug: {GetNumberFromShortMonth("aug")}");
Console.WriteLine($"Sep: {GetNumberFromShortMonth("SEP")}");
Console.WriteLine($"Oct: {GetNumberFromShortMonth("oCt")}");
Console.WriteLine($"Nov: {GetNumberFromShortMonth("NOV")}");
Console.WriteLine($"Dec: {GetNumberFromShortMonth("dec")}");
Console.WriteLine($"Empty string returns NotFound: {GetNumberFromShortMonth("") == NotFound}");
Console.WriteLine($"Too short returns NotFound: {GetNumberFromShortMonth("De") == NotFound}");
Console.WriteLine($"Too long returns NotFound: {GetNumberFromShortMonth("Dece") == NotFound}");
Console.WriteLine($"Only whitespace returns NotFound: {GetNumberFromShortMonth(" ") == NotFound}");
}
/// <summary>
/// Get the number of the month from the short month name or -1 if not found.
/// </summary>
/// <param name = "month"></param>
/// <returns></returns>
private static int GetNumberFromShortMonth(string month)
{
const int NotFound = -1;
if (month.Length != 3 || string.IsNullOrWhiteSpace(month))
{
return NotFound;
}
var index = Array.IndexOf(DateTimeFormatInfo.InvariantInfo.AbbreviatedMonthNames, NormalizeCasing(month));
return index == NotFound ? NotFound : index + 1;
}
// internal method: assuming month is a three character, non-empty string
private static string NormalizeCasing(string month)
{
#if NET
return string.Create(month.Length, month, (chars, name) =>
{
name.CopyTo(chars);
EnsureCasing(chars);
});
#else
char[] chars = month.ToCharArray();
EnsureCasing(chars);
return new string(chars);
#endif
}
private static void EnsureCasing(Span<char> chars)
{
for (int i = 0; i < chars.Length; i++)
{
if (i == 0)
{
chars[i] = char.ToUpperInvariant(chars[i]);
}
else
{
chars[i] = char.ToLowerInvariant(chars[i]);
}
}
}
}
Ожидаемый результат:
Jan: 1
Feb: 2
Mar: 3
Apr: 4
May: 5
Jun: 6
Jul: 7
Aug: 8
Sep: 9
Oct: 10
Nov: 11
Dec: 12
Empty string returns NotFound: True
Too short returns NotFound: True
Too long returns NotFound: True
Only whitespace returns NotFound: True
Обратите внимание: здесь я использую he
InvariantInfo
, который возвращает 12 месяцев и пустую строку. Существует также CurrentInfo, который использует текущий календарь и может возвращать 13 фактических значений, поскольку для некоторых календарей существует 13 месяцев. Поэтому в зависимости от того, нужна ли вам поддержка, вам придется выбрать соответствующую информацию.
Да, вы правы. Вы можете сделать именно то, что просили.