11

我们有一个应用程序解析以下格式的日期/时间值:

2009-10-10 09:19:12.124
2009-10-10 12:13:14.852
2009-10-10 13:00:00
2009-10-10 15:23:32.022

一个特定的服务器突然(今天)开始无法解析任何时间 13:00:00 或更晚。这个特定的客户端有五台服务器,只有一台有问题。我们有几十个其他客户端,总共有数百台服务器,没有问题。

System.FormatException: String was not recognized as a valid DateTime.
at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
at System.DateTime.Parse(String s, IFormatProvider provider)
at System.Convert.ToDateTime(String value, IFormatProvider provider)
at System.String.System.IConvertible.ToDateTime(IFormatProvider provider)
at System.Convert.ToDateTime(Object value)

我使用 DateTime.Parse(s, CultureInfo.CurrentCulture) 与 DateTime.Parse(s, CultureInfo.InvariantCulture) 进行了测试,问题只出现在 CurrentCulture 上。但是,CurrentCulture 就像所有其他服务器一样是“en-US”,我在区域或语言设置中没有什么不同。

有没有人见过这个?与我可以调查的内容相关的建议?

编辑:谢谢你到目前为止的答案。但是,我正在寻找有关要研究什么配置的建议,这可能会导致它突然改变行为并停止工作,因为它已经工作了多年并在数百个其他服务器上工作。我已经为下一个版本更改了它,但我正在寻找配置更改以在当前安装的过渡期间修复此问题。

4

8 回答 8

7

如果您确切知道格式,请告诉应用程序它是什么 - 使用DateTime.ParseExact而不是仅DateTime.Parse. (正如其他人所说,还要指定不变的文化,以消除更多的变化。)这给了你更多的控制权:

using System;
using System.Globalization;

class Test
{
    static void Main()
    {
        Parse("2009-10-10 09:19:12.124");
        Parse("2009-10-10 12:13:14.852");
        Parse("2009-10-10 13:00:00");
        Parse("2009-10-10 15:23:32.022");
    }

    static readonly string ShortFormat = "yyyy-MM-dd HH:mm:ss";
    static readonly string LongFormat = "yyyy-MM-dd HH:mm:ss.fff";

    static readonly string[] Formats = { ShortFormat, LongFormat };

    static void Parse(string text)
    {
        // Adjust styles as per requirements
        DateTime result = DateTime.ParseExact(text, Formats, 
                                              CultureInfo.InvariantCulture,
                                              DateTimeStyles.AssumeUniversal);
        Console.WriteLine(result);
    }
}
于 2009-10-16T19:11:25.863 回答
3

我们也遇到了同样的问题。只需回收您的应用程序池。

于 2010-03-15T17:05:35.490 回答
3

我们有一个在 Windows 2003 服务器上运行的 C# .NET 2.0 Web 服务。该服务已经运行了两年多。我们最近开始在该应用程序中遇到错误。错误消息是“字符串未被识别为有效的日期时间”。另一个 web 服务返回一个日期,该函数应该返回一个值,如

“2010 年 5 月 10 日上午 12:00:00”

当错误发生时,函数返回

“2010 年 5 月 10 日 12:00:00”

不正确的返回最后有空格并且没有 AM。

在接下来的几周内,这个问题出现并消失了好几次。在检查 Windows 日志后,我们注意到错误的开始和结束时间与应用程序池回收(默认情况下)每 29 小时发生一次(在一两分钟内)一致。此问题仅出现在生产 Web 服务器上,而不会出现在开发或测试服务器上。我们尝试更换服务器,一个月没有错误。现在错误又开始了。我们手动重置池,问题立即消失。我们不希望将其视为可接受的解决方案,因为池会定期回收。我们不知道是否需要池回收,但我们认为定期回收有助于提高应用程序性能。

Web 应用程序已经使用 ParseExact(),但格式字符串如下所示:

“yyyy-MM-ddHH:mm:ss.0Z”

代替

“yyyy-MM-dd HH:mm:ss”

Jon Skeet 在此线程中建议。我不知道这是否会有很大的不同。

我们还检查了文化设置。

问题似乎很明显是从应用程序池回收开始的,但我不知道在回收期间会发生什么。大多数时候循环没有负面影响,当错误确实发生时,下一次循环总是停止错误。

于 2010-05-21T20:40:03.147 回答
2

解决方法很简单,使用CultureInfo.InvariantCulture. 对于样本数据,这是唯一明智的做法。

我知道这并不能解释差异,但是您的软件确实不应该依赖“默认”文化(可能在 UI 中除外)。

于 2009-10-16T19:12:57.023 回答
1

我刚刚找到了一些有关导致此问题的原因的信息。我们的 C# 客户端将业务日期(仅限日期)作为字符串值发送到 Web 服务。Web 服务将 SqlParameter 中的此字符串传递给 SqlCommand 到接受datetime业务日期参数的存储过程。

客户的系统突然出现异常。我使用 SQL Server Profiler 观察 RPC 调用并注意到日期参数突然有一个时间分量。这应该是仅日期值 - 即 10/27/2012 12:00:00 AM。

我修改了存储过程以添加一个WAITFOR DELAY '00:01:00'. 然后,我在调用此存储过程时获取了 Web 服务的内存转储。

检查内存转储,我发现客户端在参数数据集中传递了正确的日期字符串“2012-10-25 00:00:00”。Web 服务在调用存储过程时不知何故弄乱了这些日期的转换。我在转储中找到了 SqlCommand 并检查了与存储过程的日期参数对应的 SqlParameter。该值为“2012 年 10 月 25 日下午 12:00:00”。

查看所有 CultureInfo 对象,我发现“en-US”的区域设置 1033 有一个很长的时间字符串“h:mm:ss tt”。AMDesignator 是“AM”,但PMDesignator 是一个空字符串!我通过运行以下命令验证了这是 C# 中错误日期的原因:

// clear the PM designator
System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator = ""
// this will yield "12/25/2012 12:00:00 " (note the extra space at the end)
Convert.ToDateTime("10/25/2012").ToString()

结果是“10/25/2012 12:00:00”,这对应于 Brian Begley 在他的回答中的内容。使用不变格式会产生非常相似的结果:

// clear the PM designator
System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator = ""
// this will yield "10/25/2012 12:00:00"
Convert.ToDateTime("10/25/2012").ToString(System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat)
// restore the PM designator to "PM"
System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator = "PM"
// this will yield "10/25/2012 00:00:00"
Convert.ToDateTime("10/25/2012").ToString(System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat)

我尚未确定导致 CultureInfo 损坏的原因。

请注意,Microsoft 已意识到此问题。链接的文章说它仅适用于 Windows Server 2003,并且有一个可用的修补程序。

于 2012-10-25T21:39:41.357 回答
0

听起来文化对象不知何故不理解军事时间表示法。老实说,我不确定从那里去哪里,但它可能会给你一个起点。

于 2009-10-16T19:05:33.687 回答
0

房产的价值是CultureInfo.DateTimeFormat多少?根据 MSDN

“用户可能会选择通过控制面板的区域和语言选项部分覆盖与当前 Windows 文化相关的一些值。例如,用户可能会选择以不同的格式显示日期或使用其他货币比文化的默认值。

如果 UseUserOverride 为 true 并且指定的区域性与 Windows 的当前区域性匹配,CultureInfo 使用这些覆盖,包括 DateTimeFormat 属性返回的 DateTimeFormatInfo 实例的属性的用户设置,以及 NumberFormat 属性返回的 NumberFormatInfo 实例的属性。如果用户设置与与 CultureInfo 关联的文化不兼容,例如,如果所选日历不是 OptionalCalendars 之一,则方法的结果和属性的值是未定义的。

在您的应用程序访问该属性之前,不会计算 DateTimeFormat 属性和 NumberFormat 属性的值。如果用户可以在应用程序运行时将当前区域性更改为新区域性,然后应用程序访问 DateTimeFormat 或 NumberFormat 属性,则应用程序将检索新区域性的默认值,而不是原始区域性的覆盖。要保留对原始当前区域性的覆盖,应用程序应在更改当前区域性之前访问 DateTimeFormat 和 NumberFormat 属性。”

可能是某些用户设置覆盖了这一点吗?

于 2009-10-16T19:13:28.840 回答
0

这是一个疯狂的猜测,但也许像这样的事件序列可能导致了问题:

  1. 管理员进入所有服务器上的控制面板国际设置,并将时间格式从“HH:mm:ss”更改为“hh:mm:ss tt”。
  2. 管理员仅在其中一台服务器上回收应用程序池(或 IIS 服务或机器)。

回收服务器上的所有新 ASP.NET 工作线程现在都将看到更改的时间格式,并且它们的DateTime.Parse方法将失败。但是,如果其他服务器仍在使用原来的工作线程,那么它们还没有检测到对当前区域性的更改DateTimeFormatInfo

这是一个非常不可能的情况,但话又说回来,你有一个非常不可能的情况。您可以尝试在所有服务器上回收相关的应用程序池,看看是否有任何变化。

于 2009-10-19T16:13:28.763 回答