我們知道數據庫中的日期時間實際上是以浮點型存儲的。故實際應用中就常會出現double與datetime類型之間互相轉換的問題。今天我們就來討論一下這個話題。
比方說我編寫了一個類來實現時間與浮點型的轉換。代碼如下:
DateTime.h
#ifndef _DATETIME__H_
#define _DATETIME__H_
#ifdef _MSC_VER
#define Q_OS_WIN32
#else
#define Q_OS_UNIX
#endif
class CDateTime;
class CDateTimeSpan;
class CDateTime
{
class TimeStruct
{
public:
short nYear;
short nMonth;
short nDay;
short nHour;
short nMinute;
short nSecond;
short nMilliseconds;
short nDayOfWeek;
};
public:
CDateTime();
CDateTime(const CDateTime& dt);
CDateTime(double dt);
CDateTime(short nYear, short nMonth, short nDay, short nHour, short nMin, short nSec, short nMillisec);
virtual ~CDateTime();
short GetYear();
short GetMonth();
short GetDay();
short GetHour();
short GetMinute();
short GetSecond();
short GetMillisecond();
short GetDayOfWeek();
short GetDayOfYear();
operator double();
operator double*();
CDateTime& operator =(const CDateTime& dtsrc);
CDateTime& operator =(const double dtsrc);
CDateTime operator +(const CDateTimeSpan& span);
CDateTime operator -(const CDateTimeSpan& span);
CDateTimeSpan operator -(const CDateTime& dt);
CDateTime& operator +=(const CDateTimeSpan span);
CDateTime& operator -=(const CDateTimeSpan span);
bool operator ==(const CDateTime& dt);
bool operator !=(const CDateTime& dt);
bool operator <(const CDateTime& dt);
bool operator >(const CDateTime& dt);
bool operator <=(const CDateTime& dt);
bool operator >=(const CDateTime& dt);
static CDateTime GetCurrentDateTime();
static bool _DateFromTm(short wYear, short wMonth, short wDay,
short wHour, short wMinute, short wSecond, short wMillisec, double& dtDest);
private:
static bool _TmFromDate(double dt, TimeStruct& systm);
protected:
double m_dt;
};
class CDateTimeSpan
{
public:
CDateTimeSpan();
CDateTimeSpan(const CDateTimeSpan& span);
CDateTimeSpan(double dblspan);
CDateTimeSpan(int lDays, int nHours, int nMins, int nSecs, int nMillisecs);
int GetDays();
int GetHours();
int GetMinutes();
int GetSeconds();
int GetMilliseconds();
double GetTotalDays();
double GetTotalHours();
double GetTotalMinutes();
double GetTotalSeconds();
double GetTotalMilliseconds();
operator double() const;
CDateTimeSpan& operator =(double dblsrc);
CDateTimeSpan& operator =(const CDateTimeSpan& span);
CDateTimeSpan operator +(const CDateTimeSpan& span);
CDateTimeSpan operator -(const CDateTimeSpan& span);
CDateTimeSpan& operator +=(const CDateTimeSpan& span);
CDateTimeSpan& operator -=(const CDateTimeSpan& span);
bool operator ==(const CDateTimeSpan& span);
bool operator !=(const CDateTimeSpan& span);
bool operator <(const CDateTimeSpan& span);
bool operator >(const CDateTimeSpan& span);
bool operator <=(const CDateTimeSpan& span);
bool operator >=(const CDateTimeSpan& span);
protected:
double m_dblspan;
};
#endif // !defined(AFX_DATETIME_H__7E16E2CB_3239_451C_9161_4CF4FB3A640A__INCLUDED_)
DateTime.cpp
#include "stdAfx.h"
#include <math.h>
#include <time.h>
#include "DateTime.h"
#if defined (Q_OS_WIN32)
#include <windows.h>
#endif
CDateTime::CDateTime() : m_dt(0.0)
{
}
CDateTime::CDateTime(const CDateTime& dt) : m_dt(dt.m_dt)
{
}
CDateTime::CDateTime(double dt) : m_dt(dt)
{
}
CDateTime::CDateTime(short nYear, short nMonth, short nDay, short nHour, short nMin, short nSec, short nMillisec)
{
if(!_DateFromTm(nYear, nMonth, nDay, nHour, nMin, nSec, nMillisec, m_dt))
{
//throw
}
}
CDateTime::~CDateTime()
{
}
short CDateTime::GetYear()
{
TimeStruct systm;
_TmFromDate(m_dt, systm);
return systm.nYear;
}
short CDateTime::GetMonth()
{
TimeStruct systm;
_TmFromDate(m_dt, systm);
return systm.nMonth;
}
short CDateTime::GetDay()
{
TimeStruct systm;
_TmFromDate(m_dt, systm);
return systm.nDay;
}
short CDateTime::GetHour()
{
TimeStruct systm;
_TmFromDate(m_dt, systm);
return systm.nHour;
}
short CDateTime::GetMinute()
{
TimeStruct systm;
_TmFromDate(m_dt, systm);
return systm.nMinute;
}
short CDateTime::GetSecond()
{
TimeStruct systm;
_TmFromDate(m_dt, systm);
return systm.nSecond;
}
short CDateTime::GetMillisecond()
{
TimeStruct systm;
_TmFromDate(m_dt, systm);
return systm.nMilliseconds;
}
short CDateTime::GetDayOfWeek()
{
TimeStruct systm;
_TmFromDate(m_dt, systm);
return systm.nDayOfWeek;
}
short CDateTime::GetDayOfYear()
{
//throw
return 0;
}
CDateTime::operator double()
{
return m_dt;
}
CDateTime::operator double*()
{
return &m_dt;
}
CDateTime& CDateTime::operator =(const CDateTime& dtsrc)
{
m_dt = dtsrc.m_dt;
return *this;
}
CDateTime& CDateTime::operator =(const double dtsrc)
{
m_dt = dtsrc;
return *this;
}
CDateTime CDateTime::operator +(const CDateTimeSpan& span)
{
CDateTime dt(m_dt + (double)span);
return dt;
}
CDateTime CDateTime::operator -(const CDateTimeSpan& span)
{
CDateTime dt(m_dt - (double)span);
return dt;
}
CDateTimeSpan CDateTime::operator -(const CDateTime& dt)
{
CDateTimeSpan _dt(m_dt - dt.m_dt);
return _dt;
}
CDateTime& CDateTime::operator +=(const CDateTimeSpan span)
{
m_dt += (double)span;
return *this;
}
CDateTime& CDateTime::operator -=(const CDateTimeSpan span)
{
m_dt -= (double)span;
return *this;
}
bool CDateTime::operator ==(const CDateTime& dt)
{
return m_dt == dt.m_dt;
}
bool CDateTime::operator !=(const CDateTime& dt)
{
return m_dt != dt.m_dt;
}
bool CDateTime::operator <(const CDateTime& dt)
{
return m_dt < dt.m_dt;
}
bool CDateTime::operator >(const CDateTime& dt)
{
return m_dt > dt.m_dt;
}
bool CDateTime::operator <=(const CDateTime& dt)
{
return m_dt <= dt.m_dt;
}
bool CDateTime::operator >=(const CDateTime& dt)
{
return m_dt >= dt.m_dt;
}
CDateTime CDateTime::GetCurrentDateTime()
{
short nYear = 0;
short nMonth = 0;
short nDay = 0;
short nHour = 0;
short nMinute = 0;
short nSecond = 0;
short nMilSec = 0;
#if defined(Q_OS_WIN32)
SYSTEMTIME t;
GetLocalTime(&t);
// GetSystemTime(&t);
nYear = t.wYear;
nMonth = t.wMonth;
nDay = t.wDay;
nHour = t.wHour;
nMinute = t.wMinute;
nSecond = t.wSecond;
nMilSec = t.wMilliseconds;
#elif defined(Q_OS_UNIX)
// posix compliant system
struct timeval tv;
gettimeofday(&tv, 0);
time_t ltime = tv.tv_sec;
time_t ldate;
time(&ldate);
tm *time, *date;
#if defined(QT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
// use the reentrant versions of localtime() and gmtime() where available
tm res;
time = localtime_r(<ime, &res);
date = localtime_r(&ldate, &res);
#else
time = localtime(<ime);
date = localtime(&ldate);
#endif // QT_THREAD_SUPPORT && _POSIX_THREAD_SAFE_FUNCTIONS
nYear = date->tm_year + 1900;
nMonth = date->tm_mon + 1;
nDay = date->tm_mday;
nHour = time->tm_hour;
nMinute = time->tm_min;
nSecond = time->tm_sec;
nMilSec = tv.tv_usec / 1000;
#else
time_t ltime; // no millisecond resolution
::time(<ime);
tm *t;
t = localtime(<ime);
nYear = t->tm_year + 1900;
nMonth = t->tm_mon + 1;
nDay = t->tm_mday;
nHour = t->tm_hour;
nMinute = t->tm_min;
nSecond = t->tm_sec;
nMilSec = 0;
#endif
CDateTime dt = CDateTime::CDateTime(nYear, nMonth, nDay, nHour, nMinute, nSecond, nMilSec);
return dt;
}
CDateTimeSpan::CDateTimeSpan() : m_dblspan(0.0)
{
}
CDateTimeSpan::CDateTimeSpan(const CDateTimeSpan& span) : m_dblspan(span.m_dblspan)
{
}
CDateTimeSpan::CDateTimeSpan(double dblspan) : m_dblspan(dblspan)
{
}
CDateTimeSpan::CDateTimeSpan(int lDays, int nHours, int nMins, int nSecs, int nMillisecs)
: m_dblspan(lDays + (double)nHours / 24.0 + (double)nMins / 1440.0 +
(double)nSecs / 86400.0 + (double)nMillisecs / 86400000.0)
{
}
int CDateTimeSpan::GetDays()
{
return (int)m_dblspan;
}
int CDateTimeSpan::GetHours()
{
return (int)((m_dblspan - floor(m_dblspan)) * 24.0);
}
int CDateTimeSpan::GetMinutes()
{
double dhours = m_dblspan * 24.0;
return (int)((dhours - floor(dhours)) * 60.0);
}
int CDateTimeSpan::GetSeconds()
{
double dmins = m_dblspan * 1440.0;
return (int)((dmins - floor(dmins)) * 60.0);
}
int CDateTimeSpan::GetMilliseconds()
{
double dsecs = m_dblspan * 86400.0;
return (int)((dsecs - floor(dsecs)) * 1000.0);
}
double CDateTimeSpan::GetTotalDays()
{
return floor(m_dblspan + 0.5);
}
double CDateTimeSpan::GetTotalHours()
{
return floor(m_dblspan * 24.0 + 0.5);
}
double CDateTimeSpan::GetTotalMinutes()
{
return floor(m_dblspan * 1440.0 + 0.5);
}
double CDateTimeSpan::GetTotalSeconds()
{
return floor(m_dblspan * 86400.0 + 0.5);
}
double CDateTimeSpan::GetTotalMilliseconds()
{
return floor(m_dblspan * 86400000.0 + 0.5);
}
CDateTimeSpan::operator double() const
{
return m_dblspan;
}
CDateTimeSpan& CDateTimeSpan::operator =(double dblsrc)
{
m_dblspan = dblsrc;
return *this;
}
CDateTimeSpan& CDateTimeSpan::operator =(const CDateTimeSpan& span)
{
m_dblspan = span.m_dblspan;
return *this;
}
CDateTimeSpan CDateTimeSpan::operator +(const CDateTimeSpan& span)
{
CDateTimeSpan _span(m_dblspan + span.m_dblspan);
return _span;
}
CDateTimeSpan CDateTimeSpan::operator -(const CDateTimeSpan& span)
{
CDateTimeSpan _span(m_dblspan - span.m_dblspan);
return _span;
}
CDateTimeSpan& CDateTimeSpan::operator +=(const CDateTimeSpan& span)
{
m_dblspan += span.m_dblspan;
return *this;
}
CDateTimeSpan& CDateTimeSpan::operator -=(const CDateTimeSpan& span)
{
m_dblspan -= span.m_dblspan;
return *this;
}
bool CDateTimeSpan::operator ==(const CDateTimeSpan& span)
{
return m_dblspan == span.m_dblspan;
}
bool CDateTimeSpan::operator !=(const CDateTimeSpan& span)
{
return m_dblspan != span.m_dblspan;
}
bool CDateTimeSpan::operator <(const CDateTimeSpan& span)
{
return m_dblspan < span.m_dblspan;
}
bool CDateTimeSpan::operator >(const CDateTimeSpan& span)
{
return m_dblspan > span.m_dblspan;
}
bool CDateTimeSpan::operator <=(const CDateTimeSpan& span)
{
return m_dblspan <= span.m_dblspan;
}
bool CDateTimeSpan::operator >=(const CDateTimeSpan& span)
{
return m_dblspan >= span.m_dblspan;
}
#define MAX_TIME_BUFFER_SIZE 128 // matches that in timecore.cpp
#define MIN_DATE (-657434L) // about year 100
#define MAX_DATE 2958465L // about year 9999
#define HALF_SECOND (1.0/172800.0)
#define HALF_MILLINSEC (1.0/172800.0/1000.0)
static int _afxMonthDays[13] =
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
bool CDateTime::_TmFromDate(double dtSrc, TimeStruct& systm)
{
// The legal range does not actually span year 0 to 9999.
if (dtSrc > MAX_DATE || dtSrc < MIN_DATE) // about year 100 to about 9999
return false;
int nDays; // Number of days since Dec. 30, 1899
int nDaysAbsolute; // Number of days since 1/1/0
int nSecsInDay; // Time in seconds since midnight
int nMinutesInDay; // Minutes in day
int n400Years; // Number of 400 year increments since 1/1/0
int n400Century; // Century within 400 year block (0,1,2 or 3)
int n4Years; // Number of 4 year increments since 1/1/0
int n4Day; // Day within 4 year block
// (0 is 1/1/yr1, 1460 is 12/31/yr4)
int n4Yr; // Year within 4 year block (0,1,2 or 3)
bool bLeap4 = true; // TRUE if 4 year block includes leap year
double dblDate = dtSrc; // tempory serial date
// If a valid date, then this conversion should not overflow
nDays = (int)dblDate;
// Round to the second
dblDate += ((dtSrc > 0.0) ? HALF_MILLINSEC : -HALF_MILLINSEC);
nDaysAbsolute = (int)dblDate + 693959L; // Add days from 1/1/0 to 12/30/1899
dblDate = fabs(dblDate);
int nMillinsecsInDay = (int)((dblDate - floor(dblDate)) * 86400.0 * 1000.0);
// Calculate the day of week (sun=1, mon=2...)
// -1 because 1/1/0 is Sat. +1 because we want 1-based
systm.nDayOfWeek = (int)((nDaysAbsolute - 1) % 7L) + 1;
// Leap years every 4 yrs except centuries not multiples of 400.
n400Years = (int)(nDaysAbsolute / 146097L);
// Set nDaysAbsolute to day within 400-year block
nDaysAbsolute %= 146097L;
// -1 because first century has extra day
n400Century = (int)((nDaysAbsolute - 1) / 36524L);
// Non-leap century
if (n400Century != 0)
{
// Set nDaysAbsolute to day within century
nDaysAbsolute = (nDaysAbsolute - 1) % 36524L;
// +1 because 1st 4 year increment has 1460 days
n4Years = (int)((nDaysAbsolute + 1) / 1461L);
if (n4Years != 0)
n4Day = (int)((nDaysAbsolute + 1) % 1461L);
else
{
bLeap4 = false;
n4Day = (int)nDaysAbsolute;
}
}
else
{
// Leap century - not special case!
n4Years = (int)(nDaysAbsolute / 1461L);
n4Day = (int)(nDaysAbsolute % 1461L);
}
if (bLeap4)
{
// -1 because first year has 366 days
n4Yr = (n4Day - 1) / 365;
if (n4Yr != 0)
n4Day = (n4Day - 1) % 365;
}
else
{
n4Yr = n4Day / 365;
n4Day %= 365;
}
// n4Day is now 0-based day of year. Save 1-based day of year, year number
int tm_yday = (int)n4Day + 1;
systm.nYear = (unsigned short)(n400Years * 400 + n400Century * 100 + n4Years * 4 + n4Yr);
// Handle leap year: before, on, and after Feb. 29.
if (n4Yr == 0 && bLeap4)
{
// Leap Year
if (n4Day == 59)
{
// Feb. 29
systm.nMonth = 2;
systm.nDay = 29;
goto DoTime;
}
// Pretend it's not a leap year for month/day comp.
if (n4Day >= 60)
--n4Day;
}
// Make n4DaY a 1-based day of non-leap year and compute
// month/day for everything but Feb. 29.
++n4Day;
// Month number always >= n/32, so save some loop time
for (systm.nMonth = (n4Day >> 5) + 1;
n4Day > _afxMonthDays[systm.nMonth]; systm.nMonth++);
systm.nDay = (int)(n4Day - _afxMonthDays[systm.nMonth-1]);
DoTime:
if (nMillinsecsInDay == 0)
systm.nHour = systm.nMinute = systm.nSecond = systm.nMilliseconds = 0;
else
{
systm.nMilliseconds = nMillinsecsInDay % 1000;
nSecsInDay = nMillinsecsInDay / 1000;
systm.nSecond = (unsigned short)(nSecsInDay % 60L);
nMinutesInDay = nSecsInDay / 60L;
systm.nMinute = (int)nMinutesInDay % 60;
systm.nHour = (int)nMinutesInDay / 60;
}
return true;
}
bool CDateTime::_DateFromTm(short nYear, short nMonth, short nDay,
short nHour, short nMinute, short nSecond, short nMillisec, double& dtDest)
{
// Validate year and month (ignore day of week and milliseconds)
if (nYear > 9999 || nMonth < 1 || nMonth > 12)
return false;
// Check for leap year and set the number of days in the month
bool bLeapYear = ((nYear & 3) == 0) &&
((nYear % 100) != 0 || (nYear % 400) == 0);
int nDaysInMonth =
_afxMonthDays[nMonth] - _afxMonthDays[nMonth-1] +
((bLeapYear && nDay == 29 && nMonth == 2) ? 1 : 0);
// Finish validating the date
if (nDay < 1 || nDay > nDaysInMonth ||
nHour > 23 || nMinute > 59 ||
nSecond > 59)
{
return false;
}
// Cache the date in days and time in fractional days
int nDate;
double dblTime;
//It is a valid date; make Jan 1, 1AD be 1
nDate = nYear*365L + nYear/4 - nYear/100 + nYear/400 +
_afxMonthDays[nMonth-1] + nDay;
// If leap year and it's before March, subtract 1:
if (nMonth <= 2 && bLeapYear)
--nDate;
// Offset so that 12/30/1899 is 0
nDate -= 693959L;
dblTime = (((int)nHour * 3600L) + // hrs in seconds
((int)nMinute * 60L) + // mins in seconds
((int)nSecond)) / 86400. + ((int)nMillisec) / 86400000.0;
dtDest = (double) nDate + ((nDate >= 0) ? dblTime : -dblTime);
return true;
}
然後我從數據庫講到一條時間記錄,存在了CString型的csDateTime裏;
while (!m_pRecordset->adoEOF)
{
csDateTime=(LPCTSTR)(_bstr_t)m_pRecordset->GetCollect("detect_date"); //獲得字段detect_date的值
csPPS=(LPCTSTR)(_bstr_t)m_pRecordset->GetCollect("pps");
csMV=(LPCTSTR)(_bstr_t)m_pRecordset->GetCollect("mv");
DateToDouble(csDateTime);
然後調用下面的函數就將cstring轉成了double;
double CReadDataBase::DateToDouble(CString csTime)
{ //2010-4-22 1:38:23
int i,j,k;
char cTemp, cData[10];
short nDateTime[6];
// nYear,nMonth,nDay,nHour,nMinute,nSecond;
j=0;
k=0;
for(i=0;i<csTime.GetLength();i++)
{
cTemp=csTime.GetAt(i);
if ((cTemp >= 48)&&(cTemp <= 57))
{
cData[j]=cTemp;
j++;
}
else
{
if ((cTemp=='-')||(cTemp==':')||(cTemp==' '))
{
cData[j]='\0';
nDateTime[k]=atoi(cData);
k++;
j=0;
}
}
if (i==csDateTime.GetLength()-1)
{
nDateTime[k]=atoi(cData);
}
}
CDateTime cDateTemp;
cDateTemp._DateFromTm(nDateTime[0],nDateTime[1],nDateTime[2],nDateTime[3],nDateTime[4],nDateTime[5],0,dDateTime);
csDateTime.Format("%f",dDateTime);
return dDateTime;
}
然後我們就可以將這個float型的值根據ieee754進行相應的轉換,然後通過協議發送出去;(ieee754這裏略去不表)
目標收到我們給出的浮點值可以進行處理後還原成時間。具體地來說,過程如下:
注:如果浮點值放到了CStirng裏,可以通過strtod進行轉換:
strtod(readdata.csDatetime,NULL)
然後通過浮點值可以構造一個cdatetime類:
CDateTime CDateTemp(strtod(readdata.csDateTime,NULL));
然後通過類的方法就可以得到時間的年、月、日、時、分、秒、甚至毫秒。。。
short year,month,day,hour,minute,second,millisecond;
year=CDateTime.GetYear();
month=CDateTime.GetMonth();
day=CDateTime.GetDay();
hour=CDateTime.GetHour();
minute=CDateTime.GetMinute();
second=CDateTime.GetSecond();
printf("%d-%d-%d %d:%d:%d\n",year,nonth,day,hour,minute,second);
the end...........................