问题 Convert.ToDateTime导致下午日期/时间值的FormatException


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

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”,在区域或语言设置中没有什么不同。

有没有人见过这个?有关我可以研究的建议?

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


3822
2017-10-16 19:02


起源



答案:


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


3
2018-03-15 17:05



是的,但是为什么?我们偶尔会遇到同样的问题。我们的Web服务将C#DateTime对象转换为字符串,并将其传递给需要smalldatetime的SQL Server数据库过程。出于某种原因,有时这会将时间缩短12小时,因此发送今天的日期与今天中午(中午12:00:00)而不是今天午夜(中午12:00:00)相同。 - Paul Williams


答案:


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


3
2018-03-15 17:05



是的,但是为什么?我们偶尔会遇到同样的问题。我们的Web服务将C#DateTime对象转换为字符串,并将其传递给需要smalldatetime的SQL Server数据库过程。出于某种原因,有时这会将时间缩短12小时,因此发送今天的日期与今天中午(中午12:00:00)而不是今天午夜(中午12:00:00)相同。 - Paul Williams


如果您完全了解格式,请告诉应用程序它是什么 - 使用 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);
    }
}

7
2017-10-16 19:11





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

“5/10/2010 12:00:00 AM”

当错误发生时,函数返回

“5/10/2010 12:00:00”

错误的返回结尾有空格,没有AM。

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

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

“YYYY-MM-ddHH:MM:ss.0Z”

代替

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

由Jon Skeet在这篇帖子中提出。我不知道这是否会产生很大的影响。

我们还检查了文化设置。

很明显,问题始于应用程序池循环,但我不知道在循环过程中引擎盖下发生了什么。大多数情况下,回收没有负面影响,当错误发生时,下一次回收总是停止错误。


3
2018-05-21 20:40



@Dan Bruton我们还没有解决它。自从我写这篇文章以来,这个问题已经引发了几次,而回收确实暂时解决了这个问题。我们正在考虑改变回收的时间,以确保它每周在同一时间发生,我们已做好准备,但我们仍然不知道真正的问题是什么。我们还与微软合作,他们似乎没有比我们更好的想法。 - Brian Begley
还有其他任何更新吗?我亲眼目睹了同样的问题,并在发生这一过程时对该进程进行了内存转储。我看到的是将日期时间存储为通用对象,然后将其作为日期时间拉回来丢失了文化信息(当然非常随机......似乎无法再现) - mpeterson


解决方案非常简单,使用方便 CultureInfo.InvariantCulture。对于样本数据来说,这是唯一明智的做法。

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


2
2017-10-16 19:12



即使使用不变的文化,我也不会依赖于默认格式 - 明确指定格式,然后很清楚您的期望。 - Jon Skeet


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

客户的系统突然行为不端。我使用SQL Server Profiler来监视RPC调用,并注意到date参数突然有一个时间组件。这应该是仅限日期的价值 - 即10/27/2012 12:00:00 AM。

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

检查内存转储,我发现客户端已经在参数的DataSet中传递了正确的日期字符串“2012-10-25 00:00:00”。 Web服务在调用存储过程时以某种方式搞砸了这些日期的转换。我在转储中找到了SqlCommand并检查了与存储过程的date参数对应的SqlParameter。该值为“10/25/2012 12:00:00 PM”。

查看所有CultureInfo对象,我发现“en-US”的语言环境1033有很长的字符串“h:mm:ss tt”。 AMD签名者是“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,并且有一个可用的修补程序。


1
2017-10-25 21:39



+1有趣的信息和类似的问题。 - Samuel Neff


听起来好像文化对象不理解军事时间符号。我老实说不知道从那里去哪里,但它可能会给你一个起点。


0
2017-10-16 19:05





什么是价值 CultureInfo.DateTimeFormat 属性? 根据MSDN

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

如果UseUserOverride为true且为   指定的文化符合当前   文化,文化信息   使用那些覆盖,包括用户   设置的属性   返回DateTimeFormatInfo实例   通过DateTimeFormat属性,和   NumberFormatInfo的属性   NumberFormat返回的实例   属性。如果用户设置是   与文化不相容   与CultureInfo相关联的   例如,如果所选日历是   不是OptionalCalendars之一   方法和值的结果   属性未定义。

DateTimeFormat的值   property和NumberFormat属性   直到你的   应用程序访问该属性。如果   用户可以改变当前   文化到新文化的同时   应用程序正在运行然后   应用程序访问   DateTimeFormat或NumberFormat   属性,应用程序检索   新文化的默认值   而不是覆盖   原始文化。为了保护   覆盖原始电流   文化,应用程序应该访问   DateTimeFormat和NumberFormat   更改当前之前的属性   文化。”

可能是某些用户设置超过这个?


0
2017-10-16 19:13





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

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

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

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


0
2017-10-19 16:13