使用当前文化定义的 12 或 24 小时格式从 DateTime 获取一天中的小时

Posted

技术标签:

【中文标题】使用当前文化定义的 12 或 24 小时格式从 DateTime 获取一天中的小时【英文标题】:Get just the hour of day from DateTime using either 12 or 24 hour format as defined by the current culture 【发布时间】:2010-06-10 13:55:58 【问题描述】:

.Net 具有用于 DateTime 的内置 ToShortTimeString() 函数,该函数使用 CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern 格式。它为 en-US 返回类似这样的内容:“5:00 pm”。对于 24 小时文化,例如 de-DE,它将返回“17:00”。

我想要的是一种只返回适用于每种文化的小时(在上述情况下为“5 pm”和“17”)的方法。最好/最干净的方法是什么?

谢谢!

【问题讨论】:

一些文化使用“H:mm”(8:11),而其他文化使用“HH:mm”(08:11)。是否要保留前导零? 嗯.. 我愿意接受。但由于我试图使字符串尽可能短,我宁愿没有前导零。 【参考方案1】:
// displays "15" because my current culture is en-GB
Console.WriteLine(DateTime.Now.ToHourString());

// displays "3 pm"
Console.WriteLine(DateTime.Now.ToHourString(new CultureInfo("en-US")));

// displays "15"
Console.WriteLine(DateTime.Now.ToHourString(new CultureInfo("de-DE")));

// ...

public static class DateTimeExtensions

    public static string ToHourString(this DateTime dt)
    
        return dt.ToHourString(null);
    

    public static string ToHourString(this DateTime dt, IFormatProvider provider)
    
        DateTimeFormatInfo dtfi = DateTimeFormatInfo.GetInstance(provider);

        string format = Regex.Replace(dtfi.ShortTimePattern, @"[^hHt\s]", "");
        format = Regex.Replace(format, @"\s+", " ").Trim();

        if (format.Length == 0)
            return "";

        if (format.Length == 1)
            format = '%' + format;

        return dt.ToString(format, dtfi);
    

【讨论】:

+1,这很干净。请注意,正如已经指出的那样,如果“格式的长度为 1,并且它不是为 DateTimeFormatInfo 定义的格式说明符字符之一”,则会引发 FormatException。也可以去掉重复的空格。另外(只是查询,我以前没见过)你是否需要对提供者进行空检查 - 从文档中我认为 .GetInstance 返回 CurrentInfo 如果提供者为空? 这与 Rawling 建议的解决方案基本相同,但使用的是正则表达式。有没有使用正则表达式确保没有重复空格的好方法? @Rawling,@InvisibleBacon:已修复。现在规范化重复的空格并处理 format.Length 为 1 的情况。我还删除了不必要的空检查。 哦,我以前没见过?=。漂亮。但是您的 Trim() 是否考虑到实际输出格式字符串以空格开头或结尾的情况,以防需要保留? (老实说,我宁愿他选择你的解决方案,它更简洁,作为扩展方法呈现等) @Rawling:它不能处理这个问题,但你会想要保留那些前导/尾随空格吗?【参考方案2】:

我会检查 CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern 是否包含“h”、“hh”、“H”、“HH”、“t”或“tt”,以及以什么顺序,然后构建您的来自这些的自定义格式字符串。

例如

zh-CN:将“h:mm tt”映射到“h tt” ja-JP:将“H:mm”映射到“H” fr-FR:将“HH:mm”映射到“HH”

然后使用 .ToString(),传入你构建的字符串。

示例代码 - 这基本上去除了所有不是 t、T、h、H 和多个空格的内容。但是,正如下面所指出的,只有一串“H”可能会失败......

string full = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern;
string sh = String.Empty;
for (int k = 0; k < full.Length; k++)

    char i = full[k];
    if (i == 'h' || i == 'H' || i == 't' || i == 'T' || (i == ' ' && (sh.Length == 0 || sh[sh.Length - 1] != ' ')))
    
        sh = sh + i;
    

if (sh.Length == 1)

  sh = sh + ' ';
  string rtnVal = DateTime.Now.ToString(sh);
  return rtnVal.Substring(0, rtnVal.Length - 1);

else

    return DateTime.Now.ToString(sh);

【讨论】:

我遇到的问题是 DateTime.Now.ToString("H") 抛出格式异常,我不知道为什么。 是的,我也注意到了。很奇怪。我发现在末尾添加一个空格可以修复它:DateTime.Now.ToString("H").TrimEnd(' ')。但这很丑陋.. 那么您是否验证了格式异常与长度为 1 的格式字符串有关?你有消息来源吗? 系统中有“h:mm.tt”的格式字符串。我不确定正确的输出是“h tt”还是“h.tt”。也许没关系。 关于 DateTime.ToString(string) 函数的 MSDN 文章说,如果 (a) 格式的长度为 1,并且它不是为 DateTimeFormatInfo 定义的格式说明符字符之一或(b) 格式不包含有效的自定义格式模式。 (a) 似乎覆盖了它。【参考方案3】:

使用这个:

bool use2fHour =
    CultureInfo
        .CurrentCulture
        .DateTimeFormat
        .ShortTimePattern.Contains("H");

【讨论】:

【参考方案4】:

您可以使用 DateTime.ToString() 并提供您想要的格式作为参数。

【讨论】:

【参考方案5】:

呃,我不想感兴趣,但现在我感兴趣!这是尊重所有文化并将 AM/PM 指示符呈现在正确位置以及识别 24 小时格式的代码,这一切都取决于文化。

基本上,此静态扩展方法被重载以采用当前文化(无参数)或指定文化。

DateTime.Now.ToTimeString()DateTime.Now.ToTimeString(someCultureInfo)

代码如下,包括示例程序:

    public static class DateTimeStaticExtensions
    
        private static int GetDesignatorIndex(CultureInfo info)
        
            if (info.DateTimeFormat
                .ShortTimePattern.StartsWith("tt"))
            
                return 0;
            
            else if (info.DateTimeFormat
                .ShortTimePattern.EndsWith("tt"))
            
                return 1;
            
            else
            
                return -1;
            
        

        private static string GetFormattedString(int hour, 
            CultureInfo info)
        
            string designator = (hour > 12 ? 
                info.DateTimeFormat.PMDesignator : 
                info.DateTimeFormat.AMDesignator);

            if (designator != "")
            
                switch (GetDesignatorIndex(info))
                
                    case 0:
                        return string.Format("0 1",
                            designator, 
                            (hour > 12 ? 
                                (hour - 12).ToString() : 
                                hour.ToString()));
                    case 1:
                        return string.Format("0 1",
                            (hour > 12 ? 
                                (hour - 12).ToString() :
                                hour.ToString()), 
                            designator);
                    default:
                        return hour.ToString();
                
            
            else
            
                return hour.ToString();
            
        

        public static string ToTimeString(this DateTime target, 
            CultureInfo info)
        
            return GetFormattedString(target.Hour, info);
        

        public static string ToTimeString(this DateTime target)
        
            return GetFormattedString(target.Hour, 
                CultureInfo.CurrentCulture);
        
    
    class Program
    
        static void Main(string[] args)
        
            var dt = new DateTime(2010, 6, 10, 6, 0, 0, 0);

            CultureInfo[] cultures = 
                CultureInfo.GetCultures(CultureTypes.SpecificCultures);
            foreach (CultureInfo culture in cultures)
            
                Console.WriteLine(
                    "0: 1 (2, 3) [Sample AM: 4 / Sample PM: 5",
                    culture.Name, culture.DateTimeFormat.ShortTimePattern,
                    (culture.DateTimeFormat.AMDesignator == "" ? 
                        "[No AM]": 
                        culture.DateTimeFormat.AMDesignator),
                    (culture.DateTimeFormat.PMDesignator == "" ? 
                        "[No PM]": 
                        culture.DateTimeFormat.PMDesignator),
                    dt.ToTimeString(culture),  // AM sample
                    dt.AddHours(12).ToTimeString(culture) // PM sample
                    );
            

            // pause program execution to review results...
            Console.WriteLine("Press enter to exit");
            Console.ReadLine();
        
    

【讨论】:

【参考方案6】: varculture = CultureInfo.CurrentCulture; bool uses24HourClock = string.IsNullOrEmpty(culture.DateTimeFormat.AMDesignator); var dt = 日期时间。现在; 字符串格式字符串 = 使用 24 小时时钟? “HH”:“h tt”; Console.WriteLine(dt.ToString(formatString,culture));

山姆的编辑:

这是证明这不起作用的代码。

var date = new DateTime(2010, 1, 1, 16, 0, 0);

foreach (CultureInfo cultureInfo in CultureInfo.GetCultures(CultureTypes.InstalledWin32Cultures))

    bool amMethod = String.IsNullOrEmpty(cultureInfo.DateTimeFormat.AMDesignator);
    bool formatMethod = cultureInfo.DateTimeFormat.ShortTimePattern.Contains("H");

    if (amMethod != formatMethod)
    
        Console.WriteLine("**** 0 AM: 1 Format: 2 Designator: 3  Time: 4",
                          cultureInfo.Name,
                          amMethod,
                          formatMethod,
                          cultureInfo.DateTimeFormat.AMDesignator,
                          date.ToString("t", cultureInfo.DateTimeFormat));
    

【讨论】:

这在许多文化中都行不通。通常 AMDesignator 被定义为'?????????'而不是在使用 24 小时时间的文化中为空或为空。此外,许多使用 24 小时时间的文化仍然指定了 AMDesignator。 啊。我刚刚检查了一种文化,发现 AM/PM 是空白的。只是假设这在所有文化中都是一致的。 有些文化甚至更奇怪。示例:af-ZA 没有 AMDesignator,但有一个 PMDesignator,并且 ShortTimePattern 为 HH:mm tt...【参考方案7】:

尝试使用 DateTime.Hour 属性。

【讨论】:

以上是关于使用当前文化定义的 12 或 24 小时格式从 DateTime 获取一天中的小时的主要内容,如果未能解决你的问题,请参考以下文章

如何在 html5 日期时间选择器中将格式从 12 小时更改为 24 小时?

从标准格式获取自定义日期时间格式

Javascript -- 检测用户的语言环境是不是设置为使用 12 小时或 24 小时时间格式

Java 获取当前时间的小时(24小时制)

Java 获取当前时间的小时(24小时制)

Java 获取当前时间的小时(24小时制)