datetime.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,201 行 · 第 1/5 页
CPP
2,201 行
///////////////////////////////////////////////////////////////////////////////
// Name: wx/datetime.h
// Purpose: implementation of time/date related classes
// Author: Vadim Zeitlin
// Modified by:
// Created: 11.05.99
// RCS-ID: $Id: datetime.cpp,v 1.136.2.1 2006/02/05 15:19:09 rgammans Exp $
// Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// parts of code taken from sndcal library by Scott E. Lee:
//
// Copyright 1993-1995, Scott E. Lee, all rights reserved.
// Permission granted to use, copy, modify, distribute and sell
// so long as the above copyright and this permission statement
// are retained in all copies.
//
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// TODO: for $DEITY sake, someone please fix the #ifdef __WXWINCE__ everywhere,
// the proper way to do it is to implement (subset of) wxStrftime() for
// CE instead of this horror!!
/*
* Implementation notes:
*
* 1. the time is stored as a 64bit integer containing the signed number of
* milliseconds since Jan 1. 1970 (the Unix Epoch) - so it is always
* expressed in GMT.
*
* 2. the range is thus something about 580 million years, but due to current
* algorithms limitations, only dates from Nov 24, 4714BC are handled
*
* 3. standard ANSI C functions are used to do time calculations whenever
* possible, i.e. when the date is in the range Jan 1, 1970 to 2038
*
* 4. otherwise, the calculations are done by converting the date to/from JDN
* first (the range limitation mentioned above comes from here: the
* algorithm used by Scott E. Lee's code only works for positive JDNs, more
* or less)
*
* 5. the object constructed for the given DD-MM-YYYY HH:MM:SS corresponds to
* this moment in local time and may be converted to the object
* corresponding to the same date/time in another time zone by using
* ToTimezone()
*
* 6. the conversions to the current (or any other) timezone are done when the
* internal time representation is converted to the broken-down one in
* wxDateTime::Tm.
*/
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "datetime.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if !defined(wxUSE_DATETIME) || wxUSE_DATETIME
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/log.h"
#endif // WX_PRECOMP
#include "wx/intl.h"
#include "wx/thread.h"
#include "wx/tokenzr.h"
#include "wx/module.h"
#include <ctype.h>
#ifdef __WINDOWS__
#include "wx/msw/wrapwin.h"
#include <winnls.h>
#ifndef __WXWINCE__
#include <locale.h>
#endif
#endif
#include "wx/datetime.h"
#include "wx/stopwatch.h" // for wxGetLocalTimeMillis()
const long wxDateTime::TIME_T_FACTOR = 1000l;
#if wxUSE_EXTENDED_RTTI
template<> void wxStringReadValue(const wxString &s , wxDateTime &data )
{
data.ParseFormat(s,wxT("%Y-%m-%d %H:%M:%S")) ;
}
template<> void wxStringWriteValue(wxString &s , const wxDateTime &data )
{
s = data.Format(wxT("%Y-%m-%d %H:%M:%S")) ;
}
wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter<wxDateTime> , wxFromStringConverter<wxDateTime>)
#endif
//
// ----------------------------------------------------------------------------
// conditional compilation
// ----------------------------------------------------------------------------
#if defined(HAVE_STRPTIME) && defined(__GLIBC__) && \
((__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
// glibc 2.0.7 strptime() is broken - the following snippet causes it to
// crash (instead of just failing):
//
// strncpy(buf, "Tue Dec 21 20:25:40 1999", 128);
// strptime(buf, "%x", &tm);
//
// so don't use it
#undef HAVE_STRPTIME
#endif // broken strptime()
#if defined(HAVE_STRPTIME) && defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
// configure detects strptime as linkable because it's in the OS X
// System library but MSL headers don't declare it.
// char *strptime(const char *, const char *, struct tm *);
// However, we DON'T want to just provide it here because we would
// crash and/or overwrite data when strptime from OS X tries
// to fill in MW's struct tm which is two fields shorter (no TZ stuff)
// So for now let's just say we don't have strptime
#undef HAVE_STRPTIME
#endif
#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()
{
static long timezone = MAXLONG; // invalid timezone
if (timezone == MAXLONG)
{
struct timeb tb;
ftime(&tb);
timezone = tb.timezone;
}
return timezone;
}
#define WX_TIMEZONE wxGetTimeZone()
#elif defined(__DARWIN__)
#define WX_GMTOFF_IN_TM
#else // unknown platform - try timezone
#define WX_TIMEZONE timezone
#endif
#endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
// debugging helper: just a convenient replacement of wxCHECK()
#define wxDATETIME_CHECK(expr, msg) \
if ( !(expr) ) \
{ \
wxFAIL_MSG(msg); \
*this = wxInvalidDateTime; \
return *this; \
}
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
class wxDateTimeHolidaysModule : public wxModule
{
public:
virtual bool OnInit()
{
wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeWorkDays);
return true;
}
virtual void OnExit()
{
wxDateTimeHolidayAuthority::ClearAllAuthorities();
wxDateTimeHolidayAuthority::ms_authorities.clear();
}
private:
DECLARE_DYNAMIC_CLASS(wxDateTimeHolidaysModule)
};
IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule, wxModule)
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// some trivial ones
static const int MONTHS_IN_YEAR = 12;
static const int SEC_PER_MIN = 60;
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;
static const long MILLISECONDS_PER_DAY = 86400000l;
// this is the integral part of JDN of the midnight of Jan 1, 1970
// (i.e. JDN(Jan 1, 1970) = 2440587.5)
static const long EPOCH_JDN = 2440587l;
// the date of JDN -0.5 (as we don't work with fractional parts, this is the
// reference date for us) is Nov 24, 4714BC
static const int JDN_0_YEAR = -4713;
static const int JDN_0_MONTH = wxDateTime::Nov;
static const int JDN_0_DAY = 24;
// the constants used for JDN calculations
static const long JDN_OFFSET = 32046l;
static const long DAYS_PER_5_MONTHS = 153l;
static const long DAYS_PER_4_YEARS = 1461l;
static const long DAYS_PER_400_YEARS = 146097l;
// this array contains the cumulated number of days in all previous months for
// normal and leap years
static const wxDateTime::wxDateTime_t gs_cumulatedDays[2][MONTHS_IN_YEAR] =
{
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
};
// ----------------------------------------------------------------------------
// global data
// ----------------------------------------------------------------------------
const wxChar * wxDefaultDateTimeFormat = wxT("%c");
const wxChar * wxDefaultTimeSpanFormat = wxT("%H:%M:%S");
// in the fine tradition of ANSI C we use our equivalent of (time_t)-1 to
// indicate an invalid wxDateTime object
const wxDateTime wxDefaultDateTime;
wxDateTime::Country wxDateTime::ms_country = wxDateTime::Country_Unknown;
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
// debugger helper: shows what the date really is
#ifdef __WXDEBUG__
extern const wxChar *wxDumpDate(const wxDateTime* dt)
{
static wxChar buf[128];
wxStrcpy(buf, dt->Format(_T("%Y-%m-%d (%a) %H:%M:%S")));
return buf;
}
#endif // Debug
// get the number of days in the given month of the given year
static inline
wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month)
{
// the number of days in month in Julian/Gregorian calendar: the first line
// is for normal years, the second one is for the leap ones
static wxDateTime::wxDateTime_t daysInMonth[2][MONTHS_IN_YEAR] =
{
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
return daysInMonth[wxDateTime::IsLeapYear(year)][month];
}
// returns the time zone in the C sense, i.e. the difference UTC - local
// (in seconds)
static 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 localtime
if ( !s_timezoneSet )
{
// just call localtime() instead of figuring out whether this system
// supports tzset(), _tzset() or something else
time_t t = 0;
struct tm *tm;
tm = localtime(&t);
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 (int)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)
static long GetTruncatedJDN(wxDateTime::wxDateTime_t day,
wxDateTime::Month mon,
int year)
{
// CREDIT: code below is by Scott E. Lee (but bugs are mine)
// check the date validity
wxASSERT_MSG(
(year > JDN_0_YEAR) ||
((year == JDN_0_YEAR) && (mon > JDN_0_MONTH)) ||
((year == JDN_0_YEAR) && (mon == JDN_0_MONTH) && (day >= JDN_0_DAY)),
_T("date out of range - can't convert to JDN")
);
// make the year positive to avoid problems with negative numbers division
year += 4800;
// months are counted from March here
int month;
if ( mon >= wxDateTime::Mar )
{
month = mon - 2;
}
else
{
month = mon + 10;
year--;
}
// now we can simply add all the contributions together
return ((year / 100) * DAYS_PER_400_YEARS) / 4
+ ((year % 100) * DAYS_PER_4_YEARS) / 4
+ (month * DAYS_PER_5_MONTHS + 2) / 5
+ day
- JDN_OFFSET;
}
#ifndef __WXWINCE__
// this function is a wrapper around strftime(3) adding error checking
static wxString CallStrftime(const wxChar *format, const tm* tm)
{
wxChar buf[4096];
// Create temp wxString here to work around mingw/cygwin bug 1046059
// http://sourceforge.net/tracker/?func=detail&atid=102435&aid=1046059&group_id=2435
wxString s;
if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) )
{
// buffer is too small?
wxFAIL_MSG(_T("strftime() failed"));
}
s = buf;
return s;
}
#endif
#ifdef HAVE_STRPTIME
// glibc2 doesn't define this in the headers unless _XOPEN_SOURCE is defined
// which, unfortunately, wreaks havoc elsewhere
#if defined(__GLIBC__) && (__GLIBC__ == 2)
extern "C" char *strptime(const char *, const char *, struct tm *);
#endif
// Unicode-friendly strptime() wrapper
static const wxChar *
CallStrptime(const wxChar *input, const char *fmt, tm *tm)
{
// the problem here is that strptime() returns pointer into the string we
// passed to it while we're really interested in the pointer into the
// original, Unicode, string so we try to transform the pointer back
#if wxUSE_UNICODE
wxCharBuffer inputMB(wxConvertWX2MB(input));
#else // ASCII
const char * const inputMB = input;
#endif // Unicode/Ascii
const char *result = strptime(inputMB, fmt, tm);
if ( !result )
return NULL;
#if wxUSE_UNICODE
// FIXME: this is wrong in presence of surrogates &c
return input + (result - inputMB.data());
#else // ASCII
return result;
#endif // Unicode/Ascii
}
#endif // HAVE_STRPTIME
// if year and/or month have invalid values, replace them with the current ones
static void ReplaceDefaultYearMonthWithCurrent(int *year,
wxDateTime::Month *month)
{
struct tm *tmNow = NULL;
if ( *year == wxDateTime::Inv_Year )
{
tmNow = wxDateTime::GetTmNow();
*year = 1900 + tmNow->tm_year;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?