65.9K
CodeProject 正在变化。 阅读更多。
Home

MFC8 中 COleDateTime 的格式化行为

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.67/5 (10投票s)

2006 年 8 月 3 日

2分钟阅读

viewsIcon

32634

downloadIcon

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 类进行了一些更改,这是直接响应他们收到的投诉的结果,但我没有看到任何地方提到他们做了什么。 我想我们只能等待观察,但在我们获得更多信息(和/或服务包)之前,这是一个可行的解决方法。

© . All rights reserved.