📄 timestmp.cpp
字号:
// **************************************************************************
// timestmp.cpp
//
// Description:
// Implements a class to contain time stamp data.
//
// DISCLAIMER:
// This programming example is provided "AS IS". As such Kepware, Inc.
// makes no claims to the worthiness of the code and does not warranty
// the code to be error free. It is provided freely and can be used in
// your own projects. If you do find this code useful, place a little
// marketing plug for Kepware in your code. While we would love to help
// every one who is trying to write a great OPC client application, the
// uniqueness of every project and the limited number of hours in a day
// simply prevents us from doing so. If you really find yourself in a
// bind, please contact Kepware's technical support. We will not be able
// to assist you with server related problems unless you are using KepServer
// or KepServerEx.
// **************************************************************************
#include "stdafx.h"
#include "timestmp.h"
// Define number of day in each month:
static unsigned short anDaysPerMonth [] =
{
31, // January
28, // February (except leap year)
31, // March
30, // April
31, // May
30, // June
31, // July
31, // August
30, // September
31, // October
30, // November
31 // December
};
// Private static member initialization:
INTLDATEFORMAT CTimeStamp::stDateFmt;
INTLTIMEFORMAT CTimeStamp::stTimeFmt;
HWND CTimeStamp::sm_hwndNotify = NULL;
CCriticalSection CTimeStamp::sm_cs;
// **************************************************************************
// NotifyWndProc ()
//
// Description:
// Hidden window proc for window created in GlobalInit (). Used to to keep
// us infored of date and time format changes.
//
// Parameters:
// HWND hWnd Handle to the window procedure that received the
// message.
// UINT msg Specifies the message.
// WPARAM wParam Specifies additional message information. The
// content of this parameter depends on the value
// of the Msg parameter.
// LPARAM lParam Specifies additional message information. The
// content of this parameter depends on the value
// of the Msg parameter.
//
// Returns:
// long - The return value is the result of the message processing and
// depends on the message.
// **************************************************************************
long WINAPI CTimeStamp::NotifyWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Processes WM_WININICHANGE (application ini file change) and WM_SETTINGCHANGE
// (system setting change) messages:
if (msg == WM_WININICHANGE || msg == WM_SETTINGCHANGE)
{
// Reset the date time format:
SetDateTimeFormat ();
// Force a repaint:
AfxGetMainWnd ()->Invalidate ();
}
// Perform default processing and return result:
return (DefWindowProc (hWnd, msg, wParam, lParam));
}
// **************************************************************************
// GlobalInit ()
//
// Description:
// This function must be called once by the application using this class
// so that a hidden window may be be created to recieve system change
// notifications. These notifications will trigger an update of the
// internal settings used when formatting dates and times.
//
// Parameters:
// none
//
// Returns:
// void
// **************************************************************************
void CTimeStamp::GlobalInit ()
{
// Create our settings change notification window if it hasn't already
// been created (indicated by NULL handle):
if (!sm_hwndNotify)
{
WNDCLASS wc;
// Get handle to current application instance (needed to define
// hidden window):
HINSTANCE hInst = AfxGetInstanceHandle ();
ASSERT (hInst);
// Define hidden window class:
wc.style = 0; // style
wc.lpfnWndProc = CTimeStamp::NotifyWndProc; // pointer to window procedure
wc.cbClsExtra = 0; // number of extra bytes to allocate following the window-class structure
wc.cbWndExtra = 0; // number of extra bytes to allocate following the window instance
wc.hIcon = NULL; // handle to the class icon
wc.hCursor = NULL; // handle to the class cursor
wc.hInstance = hInst; // handle to the instance that contains the window procedure for the class
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); // handle to the class background brush
wc.lpszMenuName = 0; // resource name of menu resource
wc.lpszClassName = _T("__TCN_CLASS__"); // window class name
// Register our hidden window class:
RegisterClass (&wc);
// Create a hidden window:
sm_hwndNotify = ::CreateWindow (
wc.lpszClassName, // registered class name
_T(""), // window name
0, // window style
0, 0, // horizontal, vertical position of window
0, 0, // window width, height
NULL, // handle to parent or owner window
NULL, // menu handle or child identifier
hInst, // handle to application instance
NULL); // window-creation data
ASSERT (sm_hwndNotify);
TRACE (_T("Time change notification window created (HWND == %08X)\n"), sm_hwndNotify);
// Initialize the statics:
SetDateTimeFormat ();
}
}
// **************************************************************************
// CTimeStamp ()
//
// Description:
// Constructor.
//
// Parameters:
// SYSTEMTIME &st Structure containing the initial time and date.
//
// Returns:
// none
// **************************************************************************
CTimeStamp::CTimeStamp (SYSTEMTIME &st)
{
// Test input data (for debugging only):
ASSERT (st.wMonth >= 1 && st.wMonth <= 12);
ASSERT (st.wHour >= 0 && st.wHour <= 23);
ASSERT (st.wMinute >= 0 && st.wMinute <= 59);
ASSERT (st.wSecond >= 0 && st.wSecond <= 59);
ASSERT (st.wMilliseconds >= 0 && st.wMilliseconds <= 999);
// Save input data:
m_st = st;
// Convert date to day of year:
ConvertDateToDays ();
// Convert time to milliseconds since midnight:
ConvertTimeToMS ();
}
// **************************************************************************
// Assign ()
//
// Description:
// Assigns time and date specified in st, and performs date and time
// conversion if specified by bInitialize.
//
// Parameters:
// SYSTEMTIME &st Structure containing the time and data.
// bool bInitialize Set to true to initialize member variables.
//
// Returns:
// void
// **************************************************************************
void CTimeStamp::Assign (SYSTEMTIME &st, bool bInitialize)
{
// Test input data (for debugging only):
ASSERT (st.wMonth >= 1 && st.wMonth <= 12);
ASSERT (st.wHour >= 0 && st.wHour <= 23);
ASSERT (st.wMinute >= 0 && st.wMinute <= 59);
ASSERT (st.wSecond >= 0 && st.wSecond <= 59);
ASSERT (st.wMilliseconds >= 0 && st.wMilliseconds <= 999);
// Save input data:
m_st = st;
// Initialize (convert date and time) if requested:
if (bInitialize)
{
ConvertDateToDays ();
ConvertTimeToMS ();
}
}
// **************************************************************************
// Assign ()
//
// Description:
// Assigns current local time and date, and performs date and time
// conversion.
//
// Parameters:
// none
//
// Returns:
// void
// **************************************************************************
void CTimeStamp::Assign ()
{
// Set member variables for local time:
GetLocalTime (&m_st);
// Convert date to day of year:
ConvertDateToDays ();
// Convert time to milliseconds since midnight:
ConvertTimeToMS ();
}
// **************************************************************************
// SetTime ()
//
// Description:
// Set the time.
//
// Parameters:
// LPCTSTR lpTime Pointer to string representation of time. Time
// must be in hh:mm:ss AM/PM format. Delimiter
// could be that specified in system time format
// instead of ":".
// bool bInitialize Set to true to initialize member variables.
//
// Returns:
// bool - true if success
// **************************************************************************
bool CTimeStamp::SetTime (LPCTSTR lpTime, bool bInitialize)
{
SYSTEMTIME tm;
int nState = 1;
TCHAR ch;
TCHAR chSep;
BOOL bPM = FALSE;
// Create a CSafeLock to make this object thread safe. Our critical
// section gets locked here, and will automatically be unlocked when the
// CSafeLock goes out of scope.
CSafeLock cs (&sm_cs);
// Formatting info must be initialized:
if (!stTimeFmt.nFmtLen)
SetDateTimeFormat ();
// Determine the selected delimiter:
chSep = *stTimeFmt.szSeparator;
// Initialize seconds in case they are not specified:
tm.wSecond = 0;
// Parse lpTime string using state machine approach. (What we see
// now determines the state. The state determines what we expect
// to see next). Initial state set to 1.
// (Loop until we get NULL terminator or nState set to -1 which
// flags an invalid time string.)
while (*lpTime && nState != -1)
{
// Save off current character, then increment pointer so we get next
// character in string next time around loop:
ch = *lpTime++;
// Skip all whitespace:
if (_istspace (ch))
continue;
// Process character according to state:
switch (nState)
{
// Looking for white space or first hour digit:
case 1:
// If character is a digit, we will assume it is the first
// digit of the hour. Save as hour and set state to 2:
if (_istdigit (ch))
{
tm.wHour = ch - _T('0'); // Convert from ASCII
++nState;
}
// Else character is invalid. Set state to -1 to break out
// of loop:
else
nState = -1;
break;
// Looking for second hour digit or separator:
case 2:
// If characer is a digit, we will assume it is the second
// digit of the hour. Update hour and set state to 3:
if (_istdigit (ch))
{
tm.wHour *= 10; // First digit parsed becomes second digit
tm.wHour += (ch - _T('0')); // Convert from ASCII
++nState;
}
// If character is a separator, set state to 4:
else if (ch == chSep || ch == _T(':'))
nState = 4;
// Else character is invalid. Set state to -1 to break out
// of loop:
else
nState = -1;
break;
// Looking for a separator:
case 3:
// If character is a separator, set state to 4:
if (ch == chSep || ch == _T(':'))
nState = 4;
// Else character is invalid. Set state to -1 to break out
// of loop:
else
nState = -1;
break;
// Looking for first minute digit:
case 4:
// If character is a digit, we will assume it is the first
// digit of minute. Save as minute and set state to 5:
if (_istdigit (ch))
{
tm.wMinute = ch - _T('0'); // Convert from ASCII
++nState;
}
// Else character is invalid. Set state to -1 to break out
// of loop:
else
nState = -1;
break;
// Looking for second minute digit, separator or first character
// of "AM" or "PM":
case 5:
// If characer is a digit, we will assume it is the second
// digit of the minute. Update minute and set state to 6:
if (_istdigit (ch))
{
tm.wMinute *= 10; // First digit parsed becomes second digit
tm.wMinute += (ch - _T('0')); // Convert from ASCII
++nState;
}
// Else if character is a separator, set state to 7:
else if (ch == chSep || ch == _T(':'))
nState = 7;
// Else if character is an "a" or "A", set state to 11:
else if (ch == _T('a') || ch == _T('A'))
nState = 11;
// Else if character is a "p" or "P", set state to 11:
else if (ch == _T('p') || ch == _T('P'))
{
nState = 11;
bPM = TRUE;
}
// Else character is invalid. Set state to -1 to break out
// of loop:
else
nState = -1;
break;
// Looking for a separator or first character of "AM" or PM":
case 6:
// If character is a separator, set state to 7:
if (ch == chSep || ch == _T(':'))
nState = 7;
// Else if character is an "a" or "A", set state to 11:
else if (ch == _T('a') || ch == _T('A'))
nState = 11;
// Else if character is a "p" or "P", set state to 11:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -