简体   繁体   English

DateTime.ToString(“T”)和DateTime.ToString(“G”)中的错误?

[英]Bug in DateTime.ToString(“T”) and DateTime.ToString(“G”)?

Microsoft specifies : as The time separator , but it seems there are at least two time separators: one between hours and minutes and another one between minutes and seconds. Microsoft指定 :作为The time separator ,但似乎至少有两个时间分隔符:一个在小时和分钟之间,另一个在分钟和秒之间。

Long time format settings in control panel http://uploads.wellisolutions.de/stackoverflow/ControlPanelLongTimeFormat.png 控制面板中的长时间格式设置http://uploads.wellisolutions.de/stackoverflow/ControlPanelLongTimeFormat.png

Long time format shown by Windows clock http://uploads.wellisolutions.de/stackoverflow/ClockCustomFormat.png Windows时钟显示的长时间格式http://uploads.wellisolutions.de/stackoverflow/ClockCustomFormat.png

Is there a way to get the specific time separators? 有没有办法获得特定的时间分隔符? I need the one between hours and minutes and the other one between minutes and seconds. 我需要几小时和几分钟之间的一个,而几分钟和几秒之间的另一个。

I would also not mind building my DateTime string in other ways, eg using the standard format string T or G , but they both don't work 我也不介意用其他方式构建我的DateTime字符串,例如使用标准格式字符串 TG ,但它们都不起作用

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

Just set the formats in .NET as you like. 只需根据需要在.NET中设置格式即可。 For example: 例如:

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

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

Then: 然后:

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

Note that I put the colon : and the slash / into single quotes (apostrophes ' ) to prevent them from being translated into whatever separator your culture has from the outset. 请注意,我将冒号:和斜杠/放入单引号(撇号' ),以防止它们从一开始就被转换为文化所具有的任何分隔符。 I just want literal colon and slash. 我只想要字面冒号和斜线。

If you don't want to write clonedProvider everywhere, change the culture permanently on your current thread: 如果您不想在clonedProvider地方编写clonedProvider ,请在当前线程上永久更改文化:

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

Do you have many threads in your application? 你的应用程序中有很多线程吗?


Edit after comment: 评论后编辑

If you want to see how the OS settings has affected your .NET format provider object, just inspect the strings: 如果要查看操作系统设置如何影响.NET格式提供程序对象,只需检查字符串:

DateTimeFormatInfo.CurrentInfo.ShortDatePattern
DateTimeFormatInfo.CurrentInfo.LongTimePattern

and so on. 等等。 I suppose your current format provider has UseUserOverride set to true , so the user settings from Windows will be visible. 我想您当前的格式提供程序已将UseUserOverride设置为true ,因此Windows中的用户设置将可见。

There is no limit to the number of "separators" the user could have typed in. For example someone might use "ddd;dd-MM,yyyy" . 用户可以键入的“分隔符”数量没有限制。例如,某人可能使用"ddd;dd-MM,yyyy" So there are three separators there. 那里有三个分隔符。 So you will have to examine the string yourself to see how many "separators" and "components" are there, and which characters the user uses as separator in each place. 因此,您必须自己检查字符串,以查看有多少“分隔符”和“组件”,以及用户在每个位置使用哪些字符作为分隔符。


Reading your question carefully, and relating to your example, I see that you typed HH-mm:ss in the Windows setting. 仔细阅读您的问题,并与您的示例相关,我看到您在Windows设置中键入了HH-mm:ss That has got a problem with it. 这有问题。 When translated to .NET syntax, the first separator - becomes the time separator. 当转换到.NET的语法,第一分离器-变成时间分隔符。 Then the next separator, the colon, in .NET is a "wildcard" meaning "substitute with time separator". 然后.NET中的下一个分隔符冒号是“通配符”,意思是“用时间分隔符替换”。 So that colon is translated to a dash as well. 因此冒号也被翻译成破折号。

You should have typed, in Windows settings, 您应该在Windows设置中键入

HH-mm':'ss

where again you protect the colon with single quotes (apostrophes). 再次用单引号(撇号) 保护结肠。

Now what if one of your users uses a non-standard separator first, and then later uses the standard separator : (or / ) without quoting the latter in single quotes? 现在,如果您的某个用户首先使用非标准分隔符,然后使用标准分隔符:/ )而不在单引号中引用后者,该怎么办? Well, in that case you are right, there is a difference between the behavior in Windows and that in .NET. 那么,在这种情况下你是对的,Windows中的行为与.NET中的行为有所不同。 Apparently users should not type formats like that. 显然用户不应该输入这样的格式。 You could call this a bug. 你可以称之为bug。

Getting separators 获得分隔符

As stated by Jeppe Stig Nielson (maybe upvote for him), there is no good way to get the second time or date separator, because in a format string like 正如Jeppe Stig Nielson所述(可能是为他投票),没有好办法获得第二次或日期分隔符,因为在格式字符串中

HH-mm/HH:mm-HH/mm

there can be multiple of them, even with the same semantics (eg between hours and minutes). 即使具有相同的语义(例如,在小时和分钟之间),也可以有多个。

Microsoft bug report 微软错误报告

I have registered at Microsoft Connect and filed the bug as DateTime.ToString("T") and DateTime.ToString("G") . 我已在Microsoft Connect注册并将错误归档为DateTime.ToString(“T”)和DateTime.ToString(“G”) If you have a Microsoft Connect account, you can vote whether or not you can reproduce the bug. 如果您有Microsoft Connect帐户,则可以投票决定是否可以重现该错误。

SSCCE to reproduce the bug SSCCE重现这个bug

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

Workaround 解决方法

As a workaround, we can use the native methods GetTimeFormat and GetDateFormat . 作为一种解决方法,我们可以使用本机方法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;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM