【问题标题】:Bug in DateTime.ToString("T") and DateTime.ToString("G")?DateTime.ToString("T") 和 DateTime.ToString("G") 中的错误?
【发布时间】:2014-03-09 21:11:27
【问题描述】:

Microsoft specifies : as The time separator,但似乎至少有两个时间分隔符:一个在小时和分钟之间,另一个在分钟和秒之间。


(来源:wellisolutions.de


(来源:wellisolutions.de

有没有办法获取特定的时间分隔符?我需要一个介于小时和分钟之间的那个,另一个介于分钟和秒之间的那个。

我也不介意以其他方式构建我的 DateTime 字符串,例如使用standard format stringTG,但它们都不起作用

mydate.ToString("T");
// Output: 20-29-46
// Expected output: 20-29:46 (as shown by Windows clock)

mydate.ToString("G");
// Output: 09/03-2014 20-29-46
// Expected output: 09/03-2014 20-29:46

【问题讨论】:

  • 这可能值得在 connect.microsoft.com 上提交报告,我希望标准格式字符串遵循操作系统设置。
  • 鉴于格式化的内置机制似乎无法按预期工作,在最坏的情况下,您始终可以使用互操作自己调用底层 OS API 以执行正确的格式化.
  • 我可以听到微软程序员对该错误报告的尖叫。
  • 您是否尝试检查当前文化并查看日期时间格式? CultureInfo c2 = CultureInfo.CurrentCulture; Console.WriteLine(c2.DateTimeFormat.ToString()); 您将看到属性“LongTimePattern”。然后也许您可以使用正则表达式检查以提取分隔符...
  • 我什至无法通过更改 Windows 设置来更改 DateTimeFormat 的短时间模式...

标签: c# .net datetime


【解决方案1】:

只要在 .NET 中设置您喜欢的格式即可。例如:

var clonedProvider = (CultureInfo)CultureInfo.CurrentCulture.Clone();

clonedProvider.DateTimeFormat.LongTimePattern = "HH-mm':'ss";
clonedProvider.DateTimeFormat.ShortDatePattern = "dd'/'MM-yyyy";

然后:

mydate.ToString("T", clonedProvider);
mydate.ToString("G", clonedProvider);

请注意,我将冒号 : 和斜杠 / 放在单引号(撇号 ')中,以防止它们从一开始就被翻译成您的文化所具有的任何分隔符。我只想要文字冒号和斜杠。

如果您不想到处写clonedProvider,请永久更改当前线程上的文化:

Thread.CurrentThread.CurrentCulture = CultureInfo.ReadOnly(clonedProvider);

您的应用程序中有很多线程吗?


编辑评论后:

如果您想查看操作系统设置如何影响您的 .NET 格式提供程序对象,只需检查字符串:

DateTimeFormatInfo.CurrentInfo.ShortDatePattern
DateTimeFormatInfo.CurrentInfo.LongTimePattern

等等。我想您当前的格式提供程序已将 UseUserOverride 设置为 true,因此 Windows 中的用户设置将可见。

用户可以输入的“分隔符”的数量没有限制。例如,有人可能会使用"ddd;dd-MM,yyyy"。所以那里有 三个 分隔符。所以你必须自己检查字符串,看看有多少“分隔符”和“组件”,以及用户在每个地方使用哪些字符作为分隔符。


仔细阅读您的问题并与您的示例相关,我看到您在 Windows 设置中输入了HH-mm:ss。这有问题。当转换为 .NET 语法时,第一个分隔符 - 成为 时间分隔符。然后,.NET 中的下一个分隔符冒号是一个“通配符”,意思是“用时间分隔符替换”。所以这个冒号也被翻译成破折号。

您应该在 Windows 设置中键入

HH-mm':'ss

你又在哪里保护用单引号(撇号)冒号。

现在,如果您的某个用户先使用非标准分隔符,然后使用标准分隔符 :(或 /)而不用单引号引用后者,该怎么办?好吧,在这种情况下,您是对的,Windows 中的行为与 .NET 中的行为有所不同。显然用户不应该输入这样的格式。 你可以称之为错误。

【讨论】:

  • 这不是 Windows 时间设置中指定的真正的 a way to get the specific time separators
  • 我不想为每个客户编译我的代码只是为了反映他的操作系统设置。
  • @Rawling 也许我理解错了。请参阅我的编辑。不能保证分隔符的数量是两个。例如,字符串中可能有零个、一个或三个分隔符。所以你应该自己检查字符串。一些病人可以使用d.yyyy,所以只有月份和年份,但没有月份编号。当您依赖用户设置时,不要做出假设。
  • @ThomasW。请参阅我的最终编辑。冒号 : 字符在 .NET 中是特殊的。你应该使用':',加上单引号',以防止对冒号的特殊解释。
  • +1 表示关于多个分隔符的点。我认为这甚至回答了我写过的唯一问题:没有办法得到“the second separator”,因为它们可能有多个。
【解决方案2】:

获取分隔符

正如 Jeppe Stig Nielson 所说(可能会支持他),没有很好的方法来获取第二个时间或日期分隔符,因为在格式字符串中像

HH-mm/HH:mm-HH/mm

它们可以有多个,即使具有相同的语义(例如在小时和分钟之间)。

微软错误报告

我已在 Microsoft Connect 注册,并将错误提交为 DateTime.ToString("T") and DateTime.ToString("G")。如果您有 Microsoft Connect 帐户,您可以投票决定是否可以重现该错误。

SSCCE 重现错误

using System;
using System.Globalization;

namespace DateTimeToString
{
    class Program
    {
        // Tested on
        // Microsoft Windows 7 Enterprise x64 Version 6.1.7601 Service Pack 1 Build 7601
        // I should have all official updates installed at the time of writing (2014-03-11)
        //
        // Microsoft Visual Studio Premium 2012 Version 11.0.61030.00 Update 4
        // Microsoft .NET Framework Version 4.5.50938
        //
        // Type: Console application x86
        // Target framework: .NET 4 Client Profile
        static void Main()
        {
            if (DateTimeFormatInfo.CurrentInfo.LongTimePattern != "HH-mm:ss" ||
                DateTimeFormatInfo.CurrentInfo.ShortDatePattern != "dd.MM/yyyy")
            {
                Console.WriteLine("Configure long time format to MM-mm:ss to reproduce the time bug.");
                Console.WriteLine("Configure short date format to dd.MM/yyyy to reproduce the date bug.");
                Console.WriteLine("Control Panel/Region and Language/Additional settings");
                return;
            }

            var dateTime = DateTime.Now;
            Console.WriteLine("Expected: " + dateTime.ToString("HH'-'mm':'ss"));
            Console.WriteLine("Actual  : " + dateTime.ToString("T"));
            Console.WriteLine();

            Console.WriteLine("Expected: " + dateTime.ToString("dd'.'MM'/'yyyy HH'-'mm':'ss"));
            Console.WriteLine("Actual  : " + dateTime.ToString("G"));
            Console.WriteLine();

            Console.WriteLine("Expected: " + dateTime.ToString("HH'-'mm':'ss"));
            Console.WriteLine("Actual  : " + dateTime.ToLongTimeString());
            Console.WriteLine();

            Console.WriteLine("Expected: " + dateTime.ToString("dd'.'MM'/'yyyy"));
            Console.WriteLine("Actual  : " + dateTime.ToShortDateString());
            Console.ReadLine();
        }
    }
}

解决方法

作为一种解决方法,我们可以使用原生方法GetTimeFormatGetDateFormat

static class Program
{
    static void Main()
    {
        var systemTime = new SystemTime(DateTime.Now);

        Console.WriteLine("ShortDatePattern (as reported by .NET): " + DateTimeFormatInfo.CurrentInfo.ShortDatePattern);
        var sbDate = new StringBuilder();
        GetDateFormat(0, 0, ref systemTime, null, sbDate, sbDate.Capacity);
        Console.WriteLine("Date string (as reported by kernel32) : " + sbDate);
        Console.WriteLine();

        Console.WriteLine("LongTimePattern (as reported by .NET) : " + DateTimeFormatInfo.CurrentInfo.LongTimePattern);
        var sbTime = new StringBuilder();
        GetTimeFormat(0, 0, ref systemTime, null, sbTime, sbTime.Capacity);
        Console.WriteLine("Time string (as reported by kernel32) : " + sbTime);

        Console.ReadKey();
    }

    [DllImport("kernel32.dll")]
    private static extern int GetDateFormat(int locale, uint dwFlags, ref SystemTime sysTime,
        string lpFormat, StringBuilder lpDateStr, int cchDate);

    [DllImport("kernel32.dll")]
    private static extern int GetTimeFormat(uint locale, uint dwFlags, ref SystemTime time, 
        string format, StringBuilder sb, int sbSize);


    [StructLayout(LayoutKind.Sequential)]
    private struct SystemTime
    {
        [MarshalAs(UnmanagedType.U2)] private readonly ushort Year;
        [MarshalAs(UnmanagedType.U2)] private readonly ushort Month;
        [MarshalAs(UnmanagedType.U2)] private readonly ushort DayOfWeek;
        [MarshalAs(UnmanagedType.U2)] private readonly ushort Day;
        [MarshalAs(UnmanagedType.U2)] private readonly ushort Hour;
        [MarshalAs(UnmanagedType.U2)] private readonly ushort Minute;
        [MarshalAs(UnmanagedType.U2)] private readonly ushort Second;
        [MarshalAs(UnmanagedType.U2)] private readonly ushort Milliseconds;

        public SystemTime(DateTime dateTime)
        {
            Year = (ushort) dateTime.Year;
            Month = (ushort) dateTime.Month;
            DayOfWeek = (ushort) dateTime.DayOfWeek;
            Day = (ushort) dateTime.Day;
            Hour = (ushort) dateTime.Hour;
            Minute = (ushort) dateTime.Minute;
            Second = (ushort) dateTime.Second;
            Milliseconds = (ushort) dateTime.Millisecond;
        }
    }
}

【讨论】:

    猜你喜欢
    • 2011-07-24
    • 2013-08-02
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-19
    • 2016-07-21
    • 1970-01-01
    相关资源
    最近更新 更多