#if !defined(wxUSE_DATETIME) || wxUSE_DATETIME
#ifndef WX_PRECOMP
- #ifdef __WXMSW__
+ #ifdef __WINDOWS__
#include "wx/msw/wrapwin.h"
#endif
#include "wx/string.h"
#endif // WX_PRECOMP
#include "wx/thread.h"
+#include "wx/time.h"
#include "wx/tokenzr.h"
#include <ctype.h>
#endif // wxUSE_EXTENDED_RTTI
-
-// ----------------------------------------------------------------------------
-// conditional compilation
-// ----------------------------------------------------------------------------
-
-#if defined(__MWERKS__) && wxUSE_UNICODE
- #include <wtime.h>
-#endif
-
-#if !defined(WX_TIMEZONE) && !defined(WX_GMTOFF_IN_TM)
- #if defined(__WXPALMOS__)
- #define WX_GMTOFF_IN_TM
- #elif defined(__BORLANDC__) || defined(__MINGW32__) || defined(__VISAGECPP__)
- #define WX_TIMEZONE _timezone
- #elif defined(__MWERKS__)
- long wxmw_timezone = 28800;
- #define WX_TIMEZONE wxmw_timezone
- #elif defined(__DJGPP__) || defined(__WINE__)
- #include <sys/timeb.h>
- #include <values.h>
- static long wxGetTimeZone()
- {
- struct timeb tb;
- ftime(&tb);
- return tb.timezone;
- }
- #define WX_TIMEZONE wxGetTimeZone()
- #elif defined(__DARWIN__)
- #define WX_GMTOFF_IN_TM
- #elif defined(__WXWINCE__) && defined(__VISUALC8__)
- // _timezone is not present in dynamic run-time library
- #if 0
- // Solution (1): use the function equivalent of _timezone
- static long wxGetTimeZone()
- {
- long t;
- _get_timezone(& t);
- return t;
- }
- #define WX_TIMEZONE wxGetTimeZone()
- #elif 1
- // Solution (2): using GetTimeZoneInformation
- static long wxGetTimeZone()
- {
- TIME_ZONE_INFORMATION tzi;
- ::GetTimeZoneInformation(&tzi);
- return tzi.Bias; // x 60
- }
- #define WX_TIMEZONE wxGetTimeZone()
- #else
- // Old method using _timezone: this symbol doesn't exist in the dynamic run-time library (i.e. using /MD)
- #define WX_TIMEZONE _timezone
- #endif
- #else // unknown platform - try timezone
- #define WX_TIMEZONE timezone
- #endif
-#endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM
-
-// NB: VC8 safe time functions could/should be used for wxMSW as well probably
-#if defined(__WXWINCE__) && defined(__VISUALC8__)
-
-struct tm *wxLocaltime_r(const time_t *t, struct tm* tm)
-{
- __time64_t t64 = *t;
- return _localtime64_s(tm, &t64) == 0 ? tm : NULL;
-}
-
-struct tm *wxGmtime_r(const time_t* t, struct tm* tm)
-{
- __time64_t t64 = *t;
- return _gmtime64_s(tm, &t64) == 0 ? tm : NULL;
-}
-
-#else // !wxWinCE with VC8
-
-#if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__)
-static wxMutex timeLock;
-#endif
-
-#ifndef HAVE_LOCALTIME_R
-struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp)
-{
-#if wxUSE_THREADS && !defined(__WINDOWS__)
- // No need to waste time with a mutex on windows since it's using
- // thread local storage for localtime anyway.
- wxMutexLocker locker(timeLock);
-#endif
-
- // Borland CRT crashes when passed 0 ticks for some reason, see SF bug 1704438
-#ifdef __BORLANDC__
- if ( !*ticks )
- return NULL;
-#endif
-
- const tm * const t = localtime(ticks);
- if ( !t )
- return NULL;
-
- memcpy(temp, t, sizeof(struct tm));
- return temp;
-}
-#endif // !HAVE_LOCALTIME_R
-
-#ifndef HAVE_GMTIME_R
-struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp)
-{
-#if wxUSE_THREADS && !defined(__WINDOWS__)
- // No need to waste time with a mutex on windows since it's
- // using thread local storage for gmtime anyway.
- wxMutexLocker locker(timeLock);
-#endif
-
-#ifdef __BORLANDC__
- if ( !*ticks )
- return NULL;
-#endif
-
- const tm * const t = gmtime(ticks);
- if ( !t )
- return NULL;
-
- memcpy(temp, gmtime(ticks), sizeof(struct tm));
- return temp;
-}
-#endif // !HAVE_GMTIME_R
-
-#endif // wxWinCE with VC8/other platforms
-
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
static const int MIN_PER_HOUR = 60;
-static const int HOURS_PER_DAY = 24;
-
static const long SECONDS_PER_DAY = 86400l;
static const int DAYS_PER_WEEK = 7;
return daysInMonth[wxDateTime::IsLeapYear(year)][month];
}
-// returns the time zone in the C sense, i.e. the difference UTC - local
-// (in seconds)
-// NOTE: not static because used by datetimefmt.cpp
-int GetTimeZone()
-{
-#ifdef WX_GMTOFF_IN_TM
- // set to true when the timezone is set
- static bool s_timezoneSet = false;
- static long gmtoffset = LONG_MAX; // invalid timezone
-
- // ensure that the timezone variable is set by calling wxLocaltime_r
- if ( !s_timezoneSet )
- {
- // just call wxLocaltime_r() instead of figuring out whether this
- // system supports tzset(), _tzset() or something else
- time_t t = 0;
- struct tm tm;
-
- wxLocaltime_r(&t, &tm);
- s_timezoneSet = true;
-
- // note that GMT offset is the opposite of time zone and so to return
- // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM
- // cases we have to negate it
- gmtoffset = -tm.tm_gmtoff;
- }
- return (int)gmtoffset;
-#else // !WX_GMTOFF_IN_TM
- return WX_TIMEZONE;
-#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM
-}
-
// return the integral part of the JDN for the midnight of the given date (to
// get the real JDN you need to add 0.5, this is, in fact, JDN of the
// noon of the previous day)
if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) )
{
- // if the format is valid, buffer must be too small?
- wxFAIL_MSG(wxT("strftime() failed"));
+ // There is one special case in which strftime() can return 0 without
+ // indicating an error: "%p" may give empty string depending on the
+ // locale, so check for it explicitly. Apparently it's really the only
+ // exception.
+ if ( format != wxS("%p") )
+ {
+ // if the format is valid, buffer must be too small?
+ wxFAIL_MSG(wxT("strftime() failed"));
+ }
buf[0] = '\0';
}
{
year = (wxDateTime_t)wxDateTime::Inv_Year;
mon = wxDateTime::Inv_Month;
- mday = 0;
- hour = min = sec = msec = 0;
+ mday =
+ yday = 0;
+ hour =
+ min =
+ sec =
+ msec = 0;
wday = wxDateTime::Inv_WeekDay;
}
bool wxDateTime::Tm::IsValid() const
{
+ if ( mon == wxDateTime::Inv_Month )
+ return false;
+
+ // We need to check this here to avoid crashing in GetNumOfDaysInMonth() if
+ // somebody passed us "(wxDateTime::Month)1000".
+ wxCHECK_MSG( mon >= wxDateTime::Jan && mon < wxDateTime::Inv_Month, false,
+ wxS("Invalid month value") );
+
// we allow for the leap seconds, although we don't use them (yet)
return (year != wxDateTime::Inv_Year) && (mon != wxDateTime::Inv_Month) &&
- (mday <= GetNumOfDaysInMonth(year, mon)) &&
+ (mday > 0 && mday <= GetNumOfDaysInMonth(year, mon)) &&
(hour < 24) && (min < 60) && (sec < 62) && (msec < 1000);
}
case wxDateTime::Local:
// get the offset from C RTL: it returns the difference GMT-local
// while we want to have the offset _from_ GMT, hence the '-'
- m_offset = -GetTimeZone();
+ m_offset = -wxGetTimeZone();
break;
case wxDateTime::GMT_12:
// return the current time with ms precision
/* static */ wxDateTime wxDateTime::UNow()
{
- return wxDateTime(wxGetLocalTimeMillis());
+ return wxDateTime(wxGetUTCTimeMillis());
}
// the values in the tm structure contain the local time
if ( tm2.tm_year == 70 && tm2.tm_mon == 0 && tm2.tm_mday == 1 )
{
return Set((time_t)(
- GetTimeZone() +
+ wxGetTimeZone() +
tm2.tm_hour * MIN_PER_HOUR * SEC_PER_MIN +
tm2.tm_min * SEC_PER_MIN +
tm2.tm_sec));
m_time *= SECONDS_PER_DAY * TIME_T_FACTOR;
// JDN corresponds to GMT, we take localtime
- Add(wxTimeSpan(hour, minute, second + GetTimeZone(), millisec));
+ Add(wxTimeSpan(hour, minute, second + wxGetTimeZone(), millisec));
}
return *this;
// use C RTL functions
struct tm tmstruct;
tm *tm;
- if ( tz.GetOffset() == -GetTimeZone() )
+ if ( tz.GetOffset() == -wxGetTimeZone() )
{
// we are working with local time
tm = wxLocaltime_r(&time, &tmstruct);
// construct Tm from these values
Tm tm;
tm.year = (int)year;
+ tm.yday = (wxDateTime_t)(dayOfYear - 1); // use C convention for day number
tm.mon = (Month)(month - 1); // algorithm yields 1 for January, not 0
tm.mday = (wxDateTime_t)day;
tm.msec = (wxDateTime_t)(timeOnly % 1000);
return *this;
}
+wxDateSpan wxDateTime::DiffAsDateSpan(const wxDateTime& dt) const
+{
+ wxASSERT_MSG( IsValid() && dt.IsValid(), wxT("invalid wxDateTime"));
+
+ // If dt is larger than this, calculations below needs to be inverted.
+ int inv = 1;
+ if ( dt > *this )
+ inv = -1;
+
+ int y = GetYear() - dt.GetYear();
+ int m = GetMonth() - dt.GetMonth();
+ int d = GetDay() - dt.GetDay();
+
+ // If month diff is negative, dt is the year before, so decrease year
+ // and set month diff to its inverse, e.g. January - December should be 1,
+ // not -11.
+ if ( m * inv < 0 || (m == 0 && d * inv < 0))
+ {
+ m += inv * MONTHS_IN_YEAR;
+ y -= inv;
+ }
+
+ // Same logic for days as for months above.
+ if ( d * inv < 0 )
+ {
+ // Use number of days in month from the month which end date we're
+ // crossing. That is month before this for positive diff, and this
+ // month for negative diff.
+ // If we're on january and using previous month, we get december
+ // previous year, but don't care, december has same amount of days
+ // every year.
+ wxDateTime::Month monthfordays = GetMonth();
+ if (inv > 0 && monthfordays == wxDateTime::Jan)
+ monthfordays = wxDateTime::Dec;
+ else if (inv > 0)
+ monthfordays = static_cast<wxDateTime::Month>(monthfordays - 1);
+
+ d += inv * wxDateTime::GetNumberOfDays(monthfordays, GetYear());
+ m -= inv;
+ }
+
+ int w = d / DAYS_PER_WEEK;
+
+ // Remove weeks from d, since wxDateSpan only keep days as the ones
+ // not in complete weeks
+ d -= w * DAYS_PER_WEEK;
+
+ return wxDateSpan(y, m, w, d);
+}
+
// ----------------------------------------------------------------------------
// Weekday and monthday stuff
// ----------------------------------------------------------------------------
{
// adjust the weekdays to non-US style.
wdYearStart = ConvertWeekDayToMondayBase(wdYearStart);
- wdTarget = ConvertWeekDayToMondayBase(wdTarget);
// quoting from http://www.cl.cam.ac.uk/~mgk25/iso-time.html:
//
//
// if Jan 1 is Thursday or less, it is in the first week of this year
- if ( wdYearStart < 4 )
- {
- // count the number of entire weeks between Jan 1 and this date
- week = (nDayInYear + wdYearStart + 6 - wdTarget)/7;
+ int dayCountFix = wdYearStart < 4 ? 6 : -1;
+
+ // count the number of week
+ week = (nDayInYear + wdYearStart + dayCountFix) / DAYS_PER_WEEK;
- // be careful to check for overflow in the next year
- if ( week == 53 && tm.mday - wdTarget > 28 )
- week = 1;
+ // check if we happen to be at the last week of previous year:
+ if ( week == 0 )
+ {
+ week = wxDateTime(31, Dec, GetYear() - 1).GetWeekOfYear();
}
- else // Jan 1 is in the last week of the previous year
+ else if ( week == 53 )
{
- // check if we happen to be at the last week of previous year:
- if ( tm.mon == Jan && tm.mday < 8 - wdYearStart )
- week = wxDateTime(31, Dec, GetYear()-1).GetWeekOfYear();
- else
- week = (nDayInYear + wdYearStart - 1 - wdTarget)/7;
+ int wdYearEnd = (wdYearStart + 364 + IsLeapYear(GetYear()))
+ % DAYS_PER_WEEK;
+
+ // Week 53 only if last day of year is Thursday or later.
+ if ( wdYearEnd < 3 )
+ week = 1;
}
}
const TimeZone& tz) const
{
Tm tm = GetTm(tz);
- wxDateTime dtMonthStart = wxDateTime(1, tm.mon, tm.year);
- int nWeek = GetWeekOfYear(flags) - dtMonthStart.GetWeekOfYear(flags) + 1;
- if ( nWeek < 0 )
+ const wxDateTime dateFirst = wxDateTime(1, tm.mon, tm.year);
+ const wxDateTime::WeekDay wdFirst = dateFirst.GetWeekDay();
+
+ if ( flags == Default_First )
{
- // this may happen for January when Jan, 1 is the last week of the
- // previous year
- nWeek += IsLeapYear(tm.year - 1) ? 53 : 52;
+ flags = GetCountry() == USA ? Sunday_First : Monday_First;
}
- return (wxDateTime::wxDateTime_t)nWeek;
+ // compute offset of dateFirst from the beginning of the week
+ int firstOffset;
+ if ( flags == Sunday_First )
+ firstOffset = wdFirst - Sun;
+ else
+ firstOffset = wdFirst == Sun ? DAYS_PER_WEEK - 1 : wdFirst - Mon;
+
+ return (wxDateTime::wxDateTime_t)((tm.mday - 1 + firstOffset)/7 + 1);
}
wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday)
wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz, bool noDST)
{
- long secDiff = GetTimeZone() + tz.GetOffset();
+ long secDiff = wxGetTimeZone() + tz.GetOffset();
// we need to know whether DST is or not in effect for this date unless
// the test disabled by the caller
wxDateTime& wxDateTime::MakeFromTimezone(const TimeZone& tz, bool noDST)
{
- long secDiff = GetTimeZone() + tz.GetOffset();
+ long secDiff = wxGetTimeZone() + tz.GetOffset();
// we need to know whether DST is or not in effect for this date unless
// the test disabled by the caller
: (wxDateTime::WeekDay)(wd - 1);
}
-#ifdef __WXMSW__
+#ifdef __WINDOWS__
wxDateTime& wxDateTime::SetFromMSWSysTime(const SYSTEMTIME& st)
{
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
}
+wxDateTime& wxDateTime::SetFromMSWSysDate(const SYSTEMTIME& st)
+{
+ return Set(st.wDay,
+ static_cast<wxDateTime::Month>(wxDateTime::Jan + st.wMonth - 1),
+ st.wYear,
+ 0, 0, 0, 0);
+}
+
void wxDateTime::GetAsMSWSysTime(SYSTEMTIME* st) const
{
const wxDateTime::Tm tm(GetTm());
st->wSecond = tm.sec;
st->wMilliseconds = tm.msec;
}
-#endif // __WXMSW__
+
+void wxDateTime::GetAsMSWSysDate(SYSTEMTIME* st) const
+{
+ const wxDateTime::Tm tm(GetTm());
+
+ st->wYear = (WXWORD)tm.year;
+ st->wMonth = (WXWORD)(tm.mon - wxDateTime::Jan + 1);
+ st->wDay = tm.mday;
+
+ st->wDayOfWeek =
+ st->wHour =
+ st->wMinute =
+ st->wSecond =
+ st->wMilliseconds = 0;
+}
+
+#endif // __WINDOWS__
#endif // wxUSE_DATETIME