MFC8 中 COleDateTime 的格式化行为






3.67/5 (10投票s)
2006 年 8 月 3 日
2分钟阅读

32634

153
针对 MFC8 中 COleDateTime 格式化行为的一个可行的解决方法。
引言
我们的大部分应用程序都使用 Oracle 数据库,在过去的 5 年里,我们一直高度依赖我们的 COleDateTime
对象处理 m_dt
值为 0.0(12/30/1899)的能力。 在我加入团队很久之前,我也依赖于此。COleDateTime
将 0.0 的值视为“有效”,并会按预期格式化日期。 直到 2006 年 2 月,我们一直使用 VC6,但随后我们的团队开始使用 VS2005。
微软似乎修改了 COleDateTime
类,使得 m_dt
值为 0.0 仍然被认为是“有效”的,但如果尝试格式化任何在 1900 年 01 月 01 日之前的日期,该类会 ASSERT
失败。 这种新的行为立即破坏了我们数百万行代码(这绝非夸张)。
我们如何解决它
像往常一样,我们时间紧迫,需要转换代码,所以我们必须想出一个快速且简单的解决方案。 我们只是在一个实用程序类中编写了一个静态函数,如下所示。 我大量使用了 CString::Replace()
方法。 有一点(我觉得有点奇怪)是,我必须使用 CString
构造函数将字面字符串传递到各种 CString
函数中。 我可能在测试应用程序中缺少一个编译器定义,或者我们的转换项目具有该定义,但无论如何,这应该可以或不使用这种奇怪之处工作。 废话不多说,这是代码
// This function assumes that the only text in the format string is, in fact, // formatting instructions for a COleDateTime. If Any other text is contained // in the string, the results will be fairly unpredictable, especially if that // format string contains numeric characters. Since our code always uses // something like "%Y/%m/%d %H:%M", this shouldn't be an issue. CString FormatOleDateTime(COleDateTime odt, LPCTSTR strFormatString) { CString strDateTime(""); CString sFormatString(strFormatString); if (odt.m_dt == 0.0) { // assumtion - we are free to do anything we want // to the date since m_dt is set to 0.0 // // consideration(s) - the user could potentially // embed the very numbers we're going to use // in our fake date, so we may want to account for them, // maybe via a table or some sort of map. // Since we're in a hurry, we'll // assume that this will never happen. :) // we require leading zeroes, so we have // to strip the # character from // the appropriate formatting commands... sFormatString.Replace(CString("%#d"), CString("%d")); sFormatString.Replace(CString("%#H"), CString("%H")); sFormatString.Replace(CString("%#I"), CString("%I")); sFormatString.Replace(CString("%#j"), CString("%j")); sFormatString.Replace(CString("%#m"), CString("%m")); sFormatString.Replace(CString("%#M"), CString("%M")); sFormatString.Replace(CString("%#S"), CString("%S")); sFormatString.Replace(CString("%#U"), CString("%U")); // I know, we're technically replacing this twice sFormatString.Replace(CString("%#w"), CString("%w")); sFormatString.Replace(CString("%#W"), CString("%W")); sFormatString.Replace(CString("%#y"), CString("%y")); sFormatString.Replace(CString("%#Y"), CString("%Y")); // the following formatting commands could potentially // screw up our carefully laid plans, so we'll eliminate them. // day of year sFormatString.Replace(CString("%j"), CString("")); // day of week (0=sunday) sFormatString.Replace(CString("%w"), CString("")); // these formatting commands need to be intercepted since they // have specific values associated with the date we're trying // to set (12/30/1899 00:00:00). // day of week - abbreviated sFormatString.Replace(CString("%a"), CString("Sat")); // day of week - fulls sFormatString.Replace(CString("%A"), CString("Saturday")); // am or pm sFormatString.Replace(CString("%p"), CString("PM")); // you'll see below why I set some fairly bizarre values here. odt.SetDateTime(1900, 12, 29, 23, 59, 59); strDateTime = odt.Format(sFormatString); // this one's easy... if (sFormatString.Find(CString("%Y")) >= 0 && strDateTime.Find(CString("1900")) >= 0) { strDateTime.Replace(CString("1900"), CString("1899")); } // if the programmer wants a 2-digit year, make a reasonable // attempt to cover the most typical formatting possibilities if (sFormatString.Find(CString("%y")) >= 0) { // my first thought was to make sure the substring I wanted to // replace was actually in the string, but that would have been // inefficient (two "find" operations, followed by the actual // replacement). So, I figured I'd just call replace() for all // of the possibilities strDateTime.Replace(CString("-00"), CString("-99")); strDateTime.Replace(CString("/00"), CString("/99")); strDateTime.Replace(CString(",00"), CString(",99")); strDateTime.Replace(CString(".00"), CString(".99")); // always do this one last strDateTime.Replace(CString("00"), CString("99")); } // now replace the hour (23 = 11pm) strDateTime.Replace(CString("23"), CString("00")); // the minutes and seconds strDateTime.Replace(CString("59"), CString("00")); // and finally the day of the month - we do // this last to account for // non-standard formatting possibilities strDateTime.Replace(CString("29"), CString("30")); } else { strDateTime = odt.Format(strFormatString); } return strDateTime; }
即将发布的 VS2005 服务包
微软声称正在发布一个服务包,并且他们对 COleDateTime
类进行了一些更改,这是直接响应他们收到的投诉的结果,但我没有看到任何地方提到他们做了什么。 我想我们只能等待观察,但在我们获得更多信息(和/或服务包)之前,这是一个可行的解决方法。