- wxCHECK_MSG( format, _T(""), _T("NULL format in wxDateTime::Format") );
-
- time_t time = GetTicks();
- if ( time != (time_t)-1 )
- {
- // use strftime()
- tm *tm;
- if ( tz.GetOffset() == -GetTimeZone() )
- {
- // we are working with local time
- tm = localtime(&time);
-
- // should never happen
- wxCHECK_MSG( tm, wxEmptyString, _T("localtime() failed") );
- }
- else
- {
- time += tz.GetOffset();
-
- if ( time >= 0 )
- {
- tm = gmtime(&time);
-
- // should never happen
- wxCHECK_MSG( tm, wxEmptyString, _T("gmtime() failed") );
- }
- else
- {
- tm = (struct tm *)NULL;
- }
- }
-
- if ( tm )
- {
- return CallStrftime(format, tm);
- }
- //else: use generic code below
- }
-
- // use a hack and still use strftime(): first find the YEAR which is a year
- // in the strftime() range (1970 - 2038) whose Jan 1 falls on the same week
- // day as the Jan 1 of the real year. Then make a copy of the format and
- // replace all occurences of YEAR in it with some unique string not
- // appearing anywhere else in it, then use strftime() to format the date in
- // year YEAR and then replace YEAR back by the real year and the unique
- // replacement string back with YEAR. Notice that "all occurences of YEAR"
- // means all occurences of 4 digit as well as 2 digit form!
-
- // NB: may be it would be simpler to "honestly" reimplement strftime()?
-
- // find the YEAR: normally, for any year X, Jan 1 or the year X + 28 is the
- // same weekday as Jan 1 of X (because the weekday advances by 1 for each
- // normal X and by 2 for each leap X, hence by 5 every 4 years or by 35
- // which is 0 mod 7 every 28 years) but this rule breaks down if there are
- // years between X and Y which are divisible by 4 but not leap (i.e.
- // divisible by 100 but not 400), hence the correction.
-
- int yearReal = GetYear(tz);
- int year = 1970 + yearReal % 28;
-
- int nCenturiesInBetween = (year / 100) - (yearReal / 100);
- int nLostWeekDays = nCenturiesInBetween - (nCenturiesInBetween / 400);
-
- // we have to gain back the "lost" weekdays...
- while ( (nLostWeekDays % 7) != 0 )
- {
- nLostWeekDays += year++ % 4 ? 1 : 2;
- }
-
- // at any rate, we can't go further than 1997 + 28!
- wxASSERT_MSG( year < 2030, _T("logic error in wxDateTime::Format") );
-
- wxString strYear, strYear2;
- strYear.Printf(_T("%d"), year);
- strYear2.Printf(_T("%d"), year % 100);
-
- // find two strings not occuring in format (this is surely not optimal way
- // of doing it... improvements welcome!)
- wxString fmt = format;
- wxString replacement = (wxChar)-1;
- while ( fmt.Find(replacement) != wxNOT_FOUND )
- {
- replacement << (wxChar)-1;
- }
-
- wxString replacement2 = (wxChar)-2;
- while ( fmt.Find(replacement) != wxNOT_FOUND )
- {
- replacement << (wxChar)-2;
- }
-
- // replace all occurences of year with it
- bool wasReplaced = fmt.Replace(strYear, replacement) > 0;
- if ( !wasReplaced )
- wasReplaced = fmt.Replace(strYear2, replacement2) > 0;
-
- // use strftime() to format the same date but in supported year
- wxDateTime dt(*this);
- dt.SetYear(year);
- wxString str = dt.Format(format, tz);
-
- // now replace the occurence of 1999 with the real year
- wxString strYearReal, strYearReal2;
- strYearReal.Printf(_T("%04d"), yearReal);
- strYearReal2.Printf(_T("%02d"), yearReal % 100);
- str.Replace(strYear, strYearReal);
- str.Replace(strYear2, strYearReal2);