繁体   English   中英

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

[英]Convert.ToDateTime causes FormatException on afternoon date/time values

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

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

谁看过这个吗? 有关我可以研究的建议?

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

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

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

我们在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在这篇帖子中提出。 我不知道这是否会产生太大的影响。

我们还检查了文化设置。

似乎很明显问题始于应用程序池回收,但我不知道在回收期间引擎盖下发生了什么。 大多数情况下,循环没有负面影响,并且当错误发生时,下一个循环始终会停止错误。

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

我知道这并不能解释这种差异,但是你的软件真的不应该依赖于'默认'文化(除了可能在UI中)。

我刚刚找到了一些有关导致此问题的原因的信息。 我们的C#客户端将业务日期(仅限日期)作为字符串值发送到Web服务。 Web服务将SqlParameter中的此字符串传递给SqlCommand,并将其传递给接受业务日期的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,并且有一个可用的修补程序。

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

CultureInfo.DateTimeFormat属性的值是多少? 根据MSDN

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

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

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

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

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

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

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

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

暂无
暂无

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

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