datetime.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,201 行 · 第 1/5 页

CPP
2,201
字号
            ret = (flags == Name_Abbr ? wxT("Nov"): wxT("November"));
            break;
        case Dec:
            ret = (flags == Name_Abbr ? wxT("Dec"): wxT("December"));
            break;
    }
    return ret;
#endif
}

/* static */
wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday,
                                    wxDateTime::NameFlags flags)
{
    wxCHECK_MSG( wday != Inv_WeekDay, wxEmptyString, _T("invalid weekday") );
#ifndef __WXWINCE__
    // take some arbitrary Sunday (but notice that the day should be such that
    // after adding wday to it below we still have a valid date, e.g. don't
    // take 28 here!)
    tm tm;
    InitTm(tm);
    tm.tm_mday = 21;
    tm.tm_mon = Nov;
    tm.tm_year = 99;

    // and offset it by the number of days needed to get the correct wday
    tm.tm_mday += wday;

    // call mktime() to normalize it...
    (void)mktime(&tm);

    // ... and call strftime()
    return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm);
#else
    wxString ret;
    switch(wday)
    {
        case Sun:
            ret = (flags == Name_Abbr ? wxT("Sun") : wxT("Sunday"));
            break;
        case Mon:
            ret = (flags == Name_Abbr ? wxT("Mon") : wxT("Monday"));
            break;
        case Tue:
            ret = (flags == Name_Abbr ? wxT("Tue") : wxT("Tuesday"));
            break;
        case Wed:
            ret = (flags == Name_Abbr ? wxT("Wed") : wxT("Wednesday"));
            break;
        case Thu:
            ret = (flags == Name_Abbr ? wxT("Thu") : wxT("Thursday"));
            break;
        case Fri:
            ret = (flags == Name_Abbr ? wxT("Fri") : wxT("Friday"));
            break;
        case Sat:
            ret = (flags == Name_Abbr ? wxT("Sat") : wxT("Saturday"));
            break;
    }
    return ret;

#endif
}

/* static */
void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm)
{
    tm tm;
    InitTm(tm);
    wxChar buffer[64];
    // @Note: Do not call 'CallStrftime' here! CallStrftime checks the return code
    // and causes an assertion failed if the buffer is to small (which is good) - OR -
    // if strftime does not return anything because the format string is invalid - OR -
    // if there are no 'am' / 'pm' tokens defined for the current locale (which is not good).
    // wxDateTime::ParseTime will try several different formats to parse the time.
    // As a result, GetAmPmStrings might get called, even if the current locale
    // does not define any 'am' / 'pm' tokens. In this case, wxStrftime would
    // assert, even though it is a perfectly legal use.
    if ( am )
    {
        if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0)
            *am = wxString(buffer);
        else
            *am = wxString();
    }
    if ( pm )
    {
        tm.tm_hour = 13;
        if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0)
            *pm = wxString(buffer);
        else
            *pm = wxString();
    }
}

// ----------------------------------------------------------------------------
// Country stuff: date calculations depend on the country (DST, work days,
// ...), so we need to know which rules to follow.
// ----------------------------------------------------------------------------

/* static */
wxDateTime::Country wxDateTime::GetCountry()
{
    // TODO use LOCALE_ICOUNTRY setting under Win32
#ifndef __WXWINCE__
    if ( ms_country == Country_Unknown )
    {
        // try to guess from the time zone name
        time_t t = time(NULL);
        struct tm *tm = localtime(&t);

        wxString tz = CallStrftime(_T("%Z"), tm);
        if ( tz == _T("WET") || tz == _T("WEST") )
        {
            ms_country = UK;
        }
        else if ( tz == _T("CET") || tz == _T("CEST") )
        {
            ms_country = Country_EEC;
        }
        else if ( tz == _T("MSK") || tz == _T("MSD") )
        {
            ms_country = Russia;
        }
        else if ( tz == _T("AST") || tz == _T("ADT") ||
                  tz == _T("EST") || tz == _T("EDT") ||
                  tz == _T("CST") || tz == _T("CDT") ||
                  tz == _T("MST") || tz == _T("MDT") ||
                  tz == _T("PST") || tz == _T("PDT") )
        {
            ms_country = USA;
        }
        else
        {
            // well, choose a default one
            ms_country = USA;
        }
    }
#else
     ms_country = USA;
#endif

    return ms_country;
}

/* static */
void wxDateTime::SetCountry(wxDateTime::Country country)
{
    ms_country = country;
}

/* static */
bool wxDateTime::IsWestEuropeanCountry(Country country)
{
    if ( country == Country_Default )
    {
        country = GetCountry();
    }

    return (Country_WesternEurope_Start <= country) &&
           (country <= Country_WesternEurope_End);
}

// ----------------------------------------------------------------------------
// DST calculations: we use 3 different rules for the West European countries,
// USA and for the rest of the world. This is undoubtedly false for many
// countries, but I lack the necessary info (and the time to gather it),
// please add the other rules here!
// ----------------------------------------------------------------------------

/* static */
bool wxDateTime::IsDSTApplicable(int year, Country country)
{
    if ( year == Inv_Year )
    {
        // take the current year if none given
        year = GetCurrentYear();
    }

    if ( country == Country_Default )
    {
        country = GetCountry();
    }

    switch ( country )
    {
        case USA:
        case UK:
            // DST was first observed in the US and UK during WWI, reused
            // during WWII and used again since 1966
            return year >= 1966 ||
                   (year >= 1942 && year <= 1945) ||
                   (year == 1918 || year == 1919);

        default:
            // assume that it started after WWII
            return year > 1950;
    }
}

/* static */
wxDateTime wxDateTime::GetBeginDST(int year, Country country)
{
    if ( year == Inv_Year )
    {
        // take the current year if none given
        year = GetCurrentYear();
    }

    if ( country == Country_Default )
    {
        country = GetCountry();
    }

    if ( !IsDSTApplicable(year, country) )
    {
        return wxInvalidDateTime;
    }

    wxDateTime dt;

    if ( IsWestEuropeanCountry(country) || (country == Russia) )
    {
        // DST begins at 1 a.m. GMT on the last Sunday of March
        if ( !dt.SetToLastWeekDay(Sun, Mar, year) )
        {
            // weird...
            wxFAIL_MSG( _T("no last Sunday in March?") );
        }

        dt += wxTimeSpan::Hours(1);

        // disable DST tests because it could result in an infinite recursion!
        dt.MakeGMT(true);
    }
    else switch ( country )
    {
        case USA:
            switch ( year )
            {
                case 1918:
                case 1919:
                    // don't know for sure - assume it was in effect all year

                case 1943:
                case 1944:
                case 1945:
                    dt.Set(1, Jan, year);
                    break;

                case 1942:
                    // DST was installed Feb 2, 1942 by the Congress
                    dt.Set(2, Feb, year);
                    break;

                    // Oil embargo changed the DST period in the US
                case 1974:
                    dt.Set(6, Jan, 1974);
                    break;

                case 1975:
                    dt.Set(23, Feb, 1975);
                    break;

                default:
                    // before 1986, DST begun on the last Sunday of April, but
                    // in 1986 Reagan changed it to begin at 2 a.m. of the
                    // first Sunday in April
                    if ( year < 1986 )
                    {
                        if ( !dt.SetToLastWeekDay(Sun, Apr, year) )
                        {
                            // weird...
                            wxFAIL_MSG( _T("no first Sunday in April?") );
                        }
                    }
                    else
                    {
                        if ( !dt.SetToWeekDay(Sun, 1, Apr, year) )
                        {
                            // weird...
                            wxFAIL_MSG( _T("no first Sunday in April?") );
                        }
                    }

                    dt += wxTimeSpan::Hours(2);

                    // TODO what about timezone??
            }

            break;

        default:
            // assume Mar 30 as the start of the DST for the rest of the world
            // - totally bogus, of course
            dt.Set(30, Mar, year);
    }

    return dt;
}

/* static */
wxDateTime wxDateTime::GetEndDST(int year, Country country)
{
    if ( year == Inv_Year )
    {
        // take the current year if none given
        year = GetCurrentYear();
    }

    if ( country == Country_Default )
    {
        country = GetCountry();
    }

    if ( !IsDSTApplicable(year, country) )
    {
        return wxInvalidDateTime;
    }

    wxDateTime dt;

    if ( IsWestEuropeanCountry(country) || (country == Russia) )
    {
        // DST ends at 1 a.m. GMT on the last Sunday of October
        if ( !dt.SetToLastWeekDay(Sun, Oct, year) )
        {
            // weirder and weirder...
            wxFAIL_MSG( _T("no last Sunday in October?") );
        }

        dt += wxTimeSpan::Hours(1);

        // disable DST tests because it could result in an infinite recursion!
        dt.MakeGMT(true);
    }
    else switch ( country )
    {
        case USA:
            switch ( year )
            {
                case 1918:
                case 1919:
                    // don't know for sure - assume it was in effect all year

                case 1943:
                case 1944:
                    dt.Set(31, Dec, year);
                    break;

                case 1945:
                    // the time was reset after the end of the WWII
                    dt.Set(30, Sep, year);
                    break;

                default:
                    // DST ends at 2 a.m. on the last Sunday of October
                    if ( !dt.SetToLastWeekDay(Sun, Oct, year) )
                    {
                        // weirder and weirder...
                        wxFAIL_MSG( _T("no last Sunday in October?") );
                    }

                    dt += wxTimeSpan::Hours(2);

                    // TODO what about timezone??
            }
            break;

        default:
            // assume October 26th as the end of the DST - totally bogus too
            dt.Set(26, Oct, year);
    }

    return dt;
}

// ----------------------------------------------------------------------------
// constructors and assignment operators
// ----------------------------------------------------------------------------

// return the current time with ms precision
/* static */ wxDateTime wxDateTime::UNow()
{
    return wxDateTime(wxGetLocalTimeMillis());
}

// the values in the tm structure contain the local time
wxDateTime& wxDateTime::Set(const struct tm& tm)
{
    struct tm tm2(tm);
    time_t timet = mktime(&tm2);

    if ( timet == (time_t)-1 )
    {
        // mktime() rather unintuitively fails for Jan 1, 1970 if the hour is
        // less than timezone - try to make it work for this case
        if ( tm2.tm_year == 70 && tm2.tm_mon == 0 && tm2.tm_mday == 1 )
        {
            return Set((time_t)(
                       GetTimeZone() +
                       tm2.tm_hour * MIN_PER_HOUR * SEC_PER_MIN +
                       tm2.tm_min * SEC_PER_MIN +
                       tm2.tm_sec));
        }

        wxFAIL_MSG( _T("mktime() failed") );

        *this = wxInvalidDateTime;

        return *this;
    }
    else
    {
        return Set(timet);
    }
}

wxDateTime& wxDateTime::Set(wxDateTime_t hour,
                            wxDateTime_t minute,
                            wxDateTime_t second,
                            wxDateTime_t millisec)
{
    // we allow seconds to be 61 to account for the leap seconds, even if we
    // don't use them really
    wxDATETIME_CHECK( hour < 24 &&
                      second < 62 &&
                      minute < 60 &&
                      millisec < 1000,
                      _T("Invalid time in wxDateTime::Set()") );

    // get the current date from system
    struct tm *tm = GetTmNow();

    wxDATETIME_CHECK( tm, _T("localtime() failed") );

    // make a copy so it isn't clobbered by the call to mktime() below
    struct tm tm1(*tm);

    // adjust the time
    tm1.tm_hour = hour;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?