/*
DateTime.js

This file holds javascript functions used for date and time manipulation.  Some date functions expect the date to be in ccyymmdd[hhmmss[nnn]] format called the CYMD format.  There are many conversion routines to convert the currect date into the expected CYMD format.

*/

//d are commented out debug code used during the creation of the function.
//c are commented out code left in to remind myself that I did think of this option.
//h are Helpful comments.

var asMonthNames = new Array("MonthPlaceHolder", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
var monthNames = asMonthNames;
var aiDaysPerMonth = new Array(0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
var daysPerMonth = aiDaysPerMonth;
var asDayNames = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");
var dayNames = asDayNames;
var asDateTokens = new Array('mdy', 'dmdy', 'ymd', 'usa', 'us', 'eur', 'eur-', 'eur.', 'ap', 'uc', 'lc', 'h', 'hh', 'n', 'nn', 's', 'ss', 'ampm', 'ampmu', 'd', 'dd', 'ddd', 'dddd', 'm', 'mm', 'mmm', 'mmmm', 'yy', 'yyyy', 'hm', 'hn', 'hms', 'hns', ' '); // do not use ap* or *ap tokens
var dateTokens = asDateTokens;
var sYEARPLACEHOLDER = "YYYY";
//var sCurrentYear = sCURRENTYEAR;

var ampm = false, upperCase = false, lowerCase = false, SUNDAY = 0;		// Global variables for convertDateToken() and dateFormat().

var TOE = '|';		// End token.  If you want | use '=|'.

// turn off the debug statements embedded throughout the code if debug has not been defined.
if (typeof(debug) == 'undefined') var debug = false; 



//-------------------------------
//
//	sLinksMonths returns a string with 
//
function sLinksMonthsAbbr()
{
	var sReturn='', sMNA, sLinkName, sLinkAddr;

	sReturn += '<';

	for (iNdx =1; iNdx<monthNames.length; iNdx++)
	{
		sMNA	= monthNames[iNdx].substr(0,3);			// get month name abbreviated
		sLinkName = '&nbsp;'+sMNA+'&nbsp;';				// add spaced on either side to make it easier to select.
//c		sLinkAddr = '#'+sMNA.toLowerCase();				// use lower case for aname.
		sLinkAddr = '#'+sPadNumber(iNdx, 2);			// use 2 digit string for aname.
		sReturn += sHref(sLinkName, sLinkAddr);
	}

	sReturn += '>';

	return sReturn;

} // end sLinksMonthsAbbr().



function getCYMD(strDate) {
}



function dAddDays(dDate, iDays) {
	dDate.setTime(dDate.getTime() + (iDays*msPerDay));	// Change the date by iDays.
	return nDate;
} // dAddDays();

// Replaced with dAddDays().
function addDays(dDate, iDays) {
	return dAddDays(dDate, iDays);
} // addDays().



function dSubDays(dDate, iDays) {
	return dAddDays(dDate, -iDays);
} // dSubDays().

// Replaced with dSubDays().
function subDays(dDate, iDays) {
	return dSubDays(dDate, iDays);
} // subDays().



function sGmtOffset(dDate, iSeconds) {
	dDate.setTime(dDate.getTime() + (iSeconds*msPerSecond));	// Change the date by iDays.
	return dDate.toGMTString();
} // sGmtDateOffset().



function dOffsetBySeconds(iSeconds) {
	var dDate=new Date();	// Create a date object with today's time and date.
	dDate.setTime(dDate.getTime() + (iSeconds*msPerSecond));	// Change the time by iSeconds.
	return dDate;
} // dOffsetBySeconds().



function getProperYear(year) {
    year = year - 0;						// Why?
    if (year < 40) return (2000 + year);
    if (year < 1900) return (1900 + year);
    return year;
}

function nths(day)
{
	var dayMod10 = day % 10;

	if ((day < 4) || (day > 20))			// Don't include the teens
	{
		if (dayMod10 == 1) return 'st';		// 31st.
		if (dayMod10 == 2) return 'nd';		// 22nd.
		if (dayMod10 == 3) return 'rd';		// 3rd.
	}
	return 'th';							// 4, 5, 6, 7, 8, 9th.

	// Alternate method.
	
	if (day == 1 || day == 21 || day == 31) return 'st';
	if (day == 2 || day == 22) return 'nd';
	if (day == 3 || day == 23) return 'rd';
	return 'th';
}



/*
The time should be read in the middle of a second (at the 500 millisecond mark) 
to avoid display skips of a second (e.g. going from 4.995 to 6.005, a delay of 
only 1.010 seconds, would be seen as going from 4 to 6 in one second).  So adjust 
the time delay to account for any code delays so the milliseconds will not creep 
towards a second boundry.  Basically, add 500 to the requested time delay and 
subtract the current millisecond reading.
If the initial Ms is above 500 then the delay will be less than the step.
If the initial Ms is too far below 500 and the percent is low the delay will 
creep up towards the 500 mark over time.
*/
function iMSDelay(iStepMs, iCurrentMs, iMaxPercent) {
	iMaxPercent = iMaxPercent || 20;	// Default delay maximum is 20% greater than normal.
	iCurrentMs = iCurrentMs || new Date().getMilliseconds();
	var iMaxDelay = iStepMs * (1+(iMaxPercent/100));	// Calculate the maximum delay.
	var iMsDelay = (iStepMs+500)-iCurrentMs;			// Adjust the delay to land in the middle of a second.
	if (iMsDelay > iMaxDelay) { iMsDelay = iMaxDelay; }	// But, do not allow interval to be too long.
	return iMsDelay;
} // iMSDelay().



/*
function makeArray0()
{
	for (i = 0; i<makeArray0.arguments.length; i++)
		this[i] = makeArray0.arguments[i];
}

var days = new makeArray0("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
*/

function mmdd(aDate)
{
//d	alert('mmdd:'+aDate);

	var rtnval;
	
	if (aDate.length == 8)				// Verify yyyymmdd format.
	{
		rtnval = aDate.slice(4, 8);
	}
	else
	{
		rtnval = '0000';
	}

	return rtnval;

} // end mmdd().

function mm(aDate)
{
//d	alert('mm: '+aDate);

	var rtnval;
	
	if (aDate.length == 8)				// Verify yyyymmdd format.
	{
		rtnval = aDate.slice(4, 6);
	}
	else
	{
		rtnval = '00';
	}

//d	alert('mm: '+rtnval);
	return rtnval;

} // end mm().

function shhmm(iMinutes)
{
	var iHours, sReturn='';

	iHours = parseInt(iMinutes/60);
	iMinutes = iMinutes - (iHours*60);

	sReturn += ''+iHours;
	sReturn += ":";
	sReturn += sPadNumber(iMinutes, 2);

//d	alert(sReturn);
	return sReturn;

}	// end shhmm().

function isDate(aDate)						//*** doesn't work!
{
	var aNewDate, bDateType, rtnval = false, temp;
	
	if (aDate instanceof Date)				// Verify aDate is a date type.
	{
		rtnval = true;
	}
	else
	{
		aNewDate = new Date(aDate);			// Attempt to convert string type to date type.
		bDateType = (aNewDate != 'Invalid Date') && (aNewDate != 'NaN');	// Netscape return Invalid Date; IE returns NaN.
//d	dwbl('isDate.d: aNewDate = '+aNewDate+"; bDateType = "+bDateType);
		if (bDateType)				// Verify aDate is now a date type.
		{
			rtnval = true;					// aDate is in a date form.
		}
		else								// check for yyyymmdd format.
		{
			temp = aDate.slice(0,4);
//d			alert('isDate.1: '+temp);
			temp = parseInt(temp);
//d			alert('isDate.2: '+temp);
			rtnval = temp > 1;
//d			alert('isDate.3: '+rtnval);

			temp = aDate.slice(4,6);
//d			alert('isDate.4: '+temp);
			temp = 0 < temp;
			temp = temp && (aDate.slice(4,6) < 13);
//d			alert('isDate.5: '+temp);
			rtnval = rtnval && temp;
//d			alert('isDate.6: '+rtnval);

			temp = aDate.slice(6,8);
//d			alert('isDate.7: '+temp);
			temp = 0 < temp;
			temp = temp && (aDate.slice(6, 8) < 32);
//d			alert('isDate.8: '+temp);
			rtnval = rtnval && temp;
//d			alert('isDate.9: '+rtnval);
		}
	}
	
    return rtnval;
}

function checkDate(aDate)
{
//d	alert('aDate = '+aDate);

	var aNewDate, rtnval = false;
	
	if (aDate instanceof Date)				// Verify aDate is a date type.
	{
		rtnval = aDate;
	}
	else
	{
		aNewDate = new Date(aDate);			// Attempt to convert string type to date type.
//d		alert('checkDate: aNewDate = '+aNewDate);
		if (aNewDate == 'NaN')				// Verify aDate is now a date type.
		{
			rtnval = false;					// aDate is not in a date form.
		}
		else
		{
			rtnval = aNewDate;
		}
	} 
    return rtnval;
}

function y2k(number) 
{
  return (number < 1000) ? number + 1900 : number;
}

function yyyymmdd(date)
{
	return ccyymmdd(date);
}

function sccyy(date)
{
	return ''+y2k(date.getYear());
}

function ccyymmdd(date)
{
  // returns a date in the ccyymmdd format
//d	alert('ccyymmdd: '+date);
  return '' +
    (y2k(date.getYear())) +
    sPadNumber(date.getMonth() + 1, 2) +
    sPadNumber(date.getDate(), 2);
}
//
// converts a string in the format ccyymmdd to a date
//
function convertDate(string) 
{
//d	alert('convertDate: '+string);
	var sYear;

	sYear = string.substring(0,4);
	if (sYear==sYEARPLACEHOLDER)
	{
		alert('==== Year is '+sYear);
		sYear = sCURRENTYEAR;
	}

	return new Date(
      sYear,
      string.substring(4,6)-1,
      string.substring(6,8)
    );
}

function getDaysPerMonth (MonthNum, Year)
{
	debug ? alert ('getDaysPerMonth('+MonthNum + sep + Year + ')') : '';

	var Days = daysPerMonth[MonthNum];
	
	if ((MonthNum == 2) && isLeapYear(Year))
	{
		Days++;
	}

	return Days;
}

function days_in_month (year, month)
{
     return 32 - new Date(year, month, 32).getDate();
}




function dayGreeting(CurrentDay)
{
	var time24 = CurrentDay.getHour();
	var greeting;
	
	if (time24 < 12)
	{
		greeting = "Good Morning";
	}
	else if (time24 < 18)
	{
		greeting = "Good Afternoon";
	}
	else
	{
		greeting = "Good Evening";
	}
	
	return greeting;
}

//-------------------------------
//
function daysUntilXmas(CurrentDay)
{
	var CurrentYear = CurrentDay.getFullYear();
	var Xmas = new Date("December, 25, 2003");	// set to Christmas of any year.

	Xmas.setFullYear(CurrentYear);				// Change any year to current year.

	var DayCount = Xmas - CurrentDay;			// # of milliseconds (ms).

	var MSperDay = 1000 * 60 * 60 * 24;			// 1000ms / sec.

	DayCount /= MSperDay;

	DayCount = Math.ceil(DayCount);

	return DayCount;
}

//-------------------------------
//
//	Check if sDate1 is before sDate2 for month and date.
//
function beforeDate (sDate1, sDate2)
{
//d	dwbl("beforeDate:"+sDate1+SEP+sDate2);	//d
	var sMMDD1, sMMDD2;
	sMMDD1 = sDate1.slice(4);			// Get Month and Day of date 1.
	sMMDD2 = sDate2.slice(4);			// Get Month and Day of date 2.
//d	dwbl(sMMDD1 + " < " + sMMDD2 + " = " + sMMDD1<sMMDD2);	//d

	return (sMMDD1 < sMMDD2);
}

//-------------------------------
//
function getMonthName (MonthNumber, mLen)
{
	debug ? alert('getMonthName: ' + MonthNumber +sep+ mLen) : '';

	var month = monthNames[MonthNumber];

	if (mLen > 0)						// mLen is optional.  If omitted function defaults to full name.
	{
		month = month.slice(0, mLen);
	}
	
	return month;
}

function getPrevMonth (Month)
{
	var PrevMonth = Month - 1;
	if (PrevMonth < 1)
	{
		PrevMonth += 12;
	}

	return PrevMonth;
}

function isLeapYear(Year)
{
	debug ? alert('isLeapYear('+Year+')') : '';
	
	var leapYear = (Year%4) == 0;
	leapYear = leapYear && (Year%100 != 0);
	leapYear = leapYear || (Year%400 == 0);

	// alert ("Year, leapYear = " + Year + ", " + leapYear);

	return leapYear;
}

/*
function LeapYear(year)		// Same as isLeapYear?
{
    if ((year/4)   != Math.floor(year/4))   return false;
    if ((year/100) != Math.floor(year/100)) return true;
    if ((year/400) != Math.floor(year/400)) return false;
    return true;
}

var accumulate    = new makeArray(  0, 31, 59, 90,120,151,181,212,243,273,304,334);
var accumulateLY  = new makeArray(  0, 31, 60, 91,121,152,182,213,244,274,305,335);

function getJulian(day,month,year)
{
    if (LeapYear(year))
        return (day + accumulateLY[month]);
    else
        return (day + accumulate[month]);
}

    var dateArray = s.split('/');
    sdate = new Date(dateArray[2],dateArray[0]-1,dateArray[1]);

var daysofmonth   = new makeArray( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
var daysofmonthLY = new makeArray( 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

function NthDay(nth,weekday,month,year) {
    if (nth > 0) return (nth-1)*7 + 1 + (7 + weekday -
DayOfWeek((nth-1)*7 + 1,month,year))%7;
    if (LeapYear(year)) var days = daysofmonthLY[month];
    else                var days = daysofmonth[month];
    return days - (DayOfWeek(days,month,year) - weekday + 7)%7;
}

function DayOfWeek(day,month,year) {
    var a = Math.floor((14 - month)/12);
    var y = year - a;
    var m = month + 12*a - 2;
    var d = (day + y + Math.floor(y/4) - Math.floor(y/100) +
Math.floor(y/400) + Math.floor((31*m)/12)) % 7;
    return d+1;
}

var today = new Date();
var year = y2k(today.getYear());

var DSTstart = new Date(year,4-1,NthDay(1,1,4,year),2,0,0);
var DSTend   = new Date(year,10-1,NthDay(-1,1,10,year),2,0,0);

function getMS(date) {
    return
Date.UTC(y2k(date.getYear()),date.getMonth(),date.getDate(),date.getHours(),date.getMinutes(),date.getSeconds())
}

var todayMS = getMS(today);
var DSTstartMS = getMS(DSTstart);
var DSTendMS = getMS(DSTend);

if (todayMS > DSTstartMS && todayMS < DSTendMS)
    document.write('Daylight Saving within effect');
else
    document.write('Daylght Saving NOT within effect');




*/

function getDayName (WeekDayNumber, startDay, dLen)
{
	var day;
	
	if (startDay == null) startDay = 0;			// startDay is optional and defaults to 0.

	WeekDayNumber += startDay;	// User can select start day where 0 = Sunday (default).
	WeekDayNumber %= 7;			// Allow for wrap around and StartDay > 6.

	day = dayNames[WeekDayNumber];

	if (dLen > 0)						// dLen is optional.  If omitted function defaults to full name.
	{
		day = day.slice(0, dLen);
	}
	
	return day;
}

function getHMMSSampm (Hours24, Minutes, Seconds)
{
	debug ? alert('getHMMSSampm : ' + Hours24 +sep+ Minutes +sep+ Seconds) : '';

	var TimeStr = "";

	TimeStr  = (Hours24 > 12) ? Hours24 - 12 : (Hours24 == 0) ? "12" : Hours24;
	TimeStr += ":";
	TimeStr += (Minutes >  9) ? Minutes : "0" + Minutes;
	TimeStr += ":";
	TimeStr += (Seconds >  9) ? Seconds : "0" + Seconds;
	TimeStr += (Hours24 > 11) ? "pm" : "am"

	return TimeStr;
}

function convertHours(Hours24)
{
	debug ? alert('convertHours : ' + Hours24) : '';

	return (Hours24 > 12) ? Hours24 - 12 : (Hours24 == 0) ? "12" : Hours24;
}





// Last revision: 2004.12.11 by Randall Ijams (rri@salestime.com).
// tokenArr = an arrar of valid tokens.
// pToken = possible token.

function isTokenPart(tokenArr, pToken)
{
	var tl = pToken.length;					// Get the size (number of characters in the possible token.

	token = pToken.toLowerCase();			// Compare strings in lower case.

	for (i=0; i<tokenArr.length; i++)		// For each token in the array...
	{
		// compare all the characters of the possible token to
		//    the same number of characters of each valid token.
		if (String(pToken) == tokenArr[i].slice(0, tl))	
		{
			return true;					// We found a match, no need to look further.
		} // end if.
		
	} // end for i.
	
	return false;							// the pToken did not match the start of any valid token.

} // end isTokenPart().












function convertDateToken(aDate, token)	// Last revision: 2004.11.29 by Randall Ijams (rri@salestime.com).
{
	/*
	----------------------------------------------------------------------------------------
	Title:   convertDateToken()
	Author:  Randall Ijams, http://www.SalesTime.com
	Legal:   Copyright (c) 1996-2005, Computer Environments
	EULA:    Open Source - ALL COPYRIGHT LINES MUST ACCOMPANY THE SCRIPT.
	Revised: 2004.12.01
	----------------------------------------------------------------------------------------
	Content:
	Convert a Token, or a combination of characters, into part of a date string.
	

	The Token should be verified with the isToken() function before calling this function.
	
	You would parce the format string and call this function once for each token found in the 
	format string.
	
	Inputs:
	aDate must be of the type Date.  It can be verified using the isDate() or checkDate() functions.
	token is a string representing the part of the date you want formatted and how you want it 
	formatted.
	
	Returns:
	A part of the date in a string format described by the characters in the Token. 
	This function will change several global variables: ampm, upperCase, and lowerCase.
	
	Modifications:
	you can add a token by adding the character string to the dateTokens array and then adding 
	another case statement to the below switch statement.

	----------------------------------------------------------------------------------------
	*/

	debug ? alert('convertDateToken : ' + aDate +sep+ token): '';
//d	alert('convertDateToken : ' + aDate +sep+ token);

	var temp = '', sReturn="";

	token = token.toLowerCase();	// Compare in lower case.

	switch (token)
	{
		case 'ap':
			ampm = true;
			sReturn = '';
			break;
		case 'uc':
			upperCase = true;
			lowerCase = false;
			sReturn = '';
			break;
		case 'lc':
			lowerCase = true;
			upperCase = false;
			sReturn = '';
			break;
		case 'h':
			sReturn = aDate.getHours();
			if (ampm)
			{
				sReturn = convertHours(sReturn);
			}
			
			break;
		case 'hh':
			sReturn = convertDateToken(aDate, 'h');
			sReturn = sPadNumber(sReturn, 2);
			break;
		case 'n':
			sReturn = aDate.getMinutes();
			break;
		case 'nn':
			sReturn = aDate.getMinutes();
			sReturn = sPadNumber(sReturn, 2);
			break;
		case 's':
			sReturn = aDate.getSeconds();
			break;
		case 'ss':
			sReturn = aDate.getSeconds();
			sReturn = sPadNumber(sReturn, 2);
			break;
		case 'd':
			sReturn = aDate.getDate();
			break;
		case 'dd':
			sReturn = aDate.getDate();
			sReturn = sPadNumber(sReturn, 2);
			break;
		case 'ddd':
			sReturn = getDayName(aDate.getDay(), SUNDAY, 3);
			break;
		case 'dddd':
			sReturn = getDayName(aDate.getDay());
			break;
		case 'm':
			sReturn = aDate.getMonth() + 1;
			break;
		case 'mm':
			sReturn = convertDateToken(aDate, 'm');
			sReturn = sPadNumber(sReturn, 2);
			break;
		case 'mmm':
		case 'w':
			sReturn = getMonthName(aDate.getMonth()+1, 3);
			break;
		case 'mmmm':
		case 'ww':
			sReturn = getMonthName(aDate.getMonth()+1);
			break;
		case 'yy':
			sReturn = aDate.getYear();
			sReturn %= 100;					// get the last 2 digits.
			sReturn = sPadNumber(sReturn, 2);
			break;
		case 'yyyy':
		case 'ccyy':
			sReturn = aDate.getFullYear();
			break;
		case 'ampm':
			hour = aDate.getHours();
			sReturn = (hour > 11) ? 'pm' : 'am';
			break;
		case 'ampmu':
			hour = aDate.getHours();
			sReturn = (hour > 11) ? 'PM' : 'AM';
			break;
		case 'hm':
		case 'hn':
			sTemp = (ampm)?'':'ap';
			sReturn = sDateFormat(aDate, sTemp+'h:nn');
//c			temp  = convertDateToken(aDate, 'h');
//c			temp += ':';
//c			sReturn = temp + convertDateToken(aDate, 'nn');
			break;
		case 'hms':
		case 'hns':
			sTemp = (ampm)?'':'ap';
			sReturn = sDateFormat(aDate, 'hm:ss');
//c			temp  = convertDateToken(aDate, 'hm');
//c			temp += ':';
//c			sReturn = temp + convertDateToken(aDate, 'ss');
			break;
		case 'mdy':
			sReturn = sDateFormat(aDate, 'mmmm d, yyyy');
//c			temp += convertDateToken(aDate, 'mmmm');
//c			temp += sNBSP;
//c			temp += convertDateToken(aDate, 'd');
//c			temp += ','+sNBSP;
//c			sReturn = temp + convertDateToken(aDate, 'yyyy');
			break;
		case 'dmdy':
			sReturn = sDateFormat(aDate, 'dddd, mdy');
//c			temp  = convertDateToken(aDate, 'dddd');
//c			temp += ','+sNBSP;
//c			sReturn = temp + convertDateToken(aDate, 'mdy');
			break;
		case 'us':
			sReturn = sDateFormat(aDate, 'm/d/yy');
//c			temp  = convertDateToken(aDate, 'm');
//c			temp += '/';
//c			temp += convertDateToken(aDate, 'd');
//c			temp += '/';
//c			sReturn = temp + convertDateToken(aDate, 'yy');
			break;
		case 'usa':
			sReturn = sDateFormat(aDate, 'm/d/yyyy');
//c			temp  = convertDateToken(aDate, 'm');
//c			temp += '/';
//c			temp += convertDateToken(aDate, 'd');
//c			temp += '/';
//c			sReturn = temp + convertDateToken(aDate, 'yyyy');
			break;
		case 'eur':
		case 'ymd':
			sReturn = sDateFormat(aDate, 'yyyymmdd');
//c			temp  = convertDateToken(aDate, 'yyyy');
//c			temp += convertDateToken(aDate, 'mm');
//c			sReturn = temp + convertDateToken(aDate, 'dd');
			break;
		case 'eur-':
			sReturn = sDateFormat(aDate, 'yyyy-mm-dd');
//c			temp  = convertDateToken(aDate, 'yyyy');
//c			temp += '-';
//c			temp += convertDateToken(aDate, 'mm');
//c			temp += '-';
//c			sReturn = temp + convertDateToken(aDate, 'dd');
			break;
		case 'eur.':
			sReturn = sDateFormat(aDate, 'yyyy.mm.dd');
//c			temp  = convertDateToken(aDate, 'yyyy');
//c			temp += '.';
//c			temp += convertDateToken(aDate, 'mm');
//c			temp += '.';
//c			sReturn = temp + convertDateToken(aDate, 'dd');
			break;
		case ' ':		// assume everything for the date is not to be wrapped.
			sReturn = sNBSP;
			break;
		default:
			sReturn = '(unknown date format code:'+token+')';	// Token is in the array but not in this switch statement!
			break;

	} // end switch.

//d	alert('date Token = '+sReturn);
	
	return sReturn;
	
} // end convertDateToken().



var giOldMilliSeconds = 0;	// Redo code to eliminate this global.?????
/*

*/
function sClock(iStep, b12Hour, bAMPMUC, bMilliSeconds){
	b12Hour = b12Hour || false;	// Default to 24 hour time format.
	bAMPMUC = bAMPMUC || false;	// Default to lower case.
	bMilliSeconds = bMilliSeconds || false;	// Default to no micro second display.

	var sReturn = '';
	var sTemp = '';
	var sAMPM = "am";
	var dNow = new Date();
	var iHours		  = dNow.getHours();
	var sHours		  = sNumberPad(iHours, 2);		// Assume 24 hour format (leading zero) for now.
	var sMinutes 	  = sNumberPad(dNow.getMinutes(), 2);
	var sSeconds 	  = sNumberPad(dNow.getSeconds(), 2);
	var iMilliSeconds = dNow.getMilliseconds();
	iDeltaMilliSeconds = iMilliSeconds - giOldMilliSeconds;	// Assume current milliseconds is later than old as executing code takes some time.
	iDeltaMilliSeconds = (iDeltaMilliSeconds + iStep) % iStep;

	giOldMilliSeconds = iMilliSeconds;	// For next iteration.
	
	if (bMilliSeconds) {
		sTemp += sRepeat(sNBSP, 10); // = '          '.
		var sMilliSeconds = sNumberPad(iMilliSeconds, 3);	// = '395'.
		sTemp += "."+sMilliSeconds;	// = '          .395'.
	} // if().
	if (b12Hour) {
		if (iHours > 12) {	// For hours 13 and above...
			sAMPM = "pm";	// Change from the default am to pm.
			iHours -= 12;	// Make hours into a 12 hour format.
		} else if (iHours > 11) {	// For hour 12...
			sAMPM = "pm";	// Change from the default am to pm.
		} // if().
		sHours = '' + iHours;	// Overwrite sHours converting iHours to string without leading 0.
		if (bAMPMUC) {
			sAMPM = sAMPM.toUpperCase();	// = AM or PM
		} // if().
		sTemp += ' '+sAMPM;	// sTemp = '.395 AM'
	} // if().
	sReturn = sHours + ":" + sMinutes + ":" + sSeconds + sTemp;

	return sReturn;
} // sClock().








function sDateFormat(dateToFormat, formatAs, DELIM)
{
	return dateFormat(dateToFormat, formatAs, DELIM);
}

function dateFormat(dateToFormat, formatAs, DELIM)
{
	/*
	----------------------------------------------------------------------------------------
	Title:   dateFormat(dateToFormat, formatAs [, delimiter])
	Author:  Randall Ijams, http://www.SalesTime.com
	Legal:   Copyright (c) 1996-2005, Computer Environments
	EULA:    Open Source - ALL COPYRIGHT LINES MUST ACCOMPANY THE SCRIPT.
	Revised: 2004.12.07
	----------------------------------------------------------------------------------------
	Content:
	Date Format with 2 parameters: the date and format string.

	The date can be either a date type or a date string.  If the date string is not correct as
	error message will be returned rather than the formatted date.  

	The format string uses the below table to format the date.  Upper, lower, and mixed cases 
	are allowed.  Any character not in the table will be treated as itself (e.g. a 'p' in the 
	format string will simply be displayed as a 'p').  The longest string match will take 
	prescedense (i.e. mmmmm will be processed as mmmm followed my m).
	
	Syntax: 
	1) document.write('Today is ' + dateFormat(new Date(), 'dddd, mmmm d, yyyy at aph:nn:ss ampmuc.'));
	2) document.write('Today is ' + dateFormat(new Date(), 'dmdy at aphms.'));
	3) document.write('You were born on ' + dateFormat('Dec 1, 1922 58:13', 'dmdy at aphns.'));
	4) document.write('Your anniversary is ' + dateFormat('1/12/55 3:24 pm', 'MDY at Hm.'));

	Results in: 
	1) Today is Tuesday, March 9, 2005 at 1:08:56 PM.			
		(long format, with todays date)
	2) Today is Tuesday, March 9, 2005 at 1:08:56 pm.			
		(abbreavated format, with todays date)
	3) You were born on Friday, December 3, 1922 at 10:13 am.	
		(long month name, military time to am/pm, 48 hours = 2 days)
	4) Your anniversary is January 12, 1955 at 15:24.			
		(no day, military time)

	Other examples - dates:

	'ddd, yyyy.mm.dd' == 'Tue, 2005.03.09'
	'dddd, mmm d, yy' == 'Tuesday, Mar 9, 05'
	'yyyymmddhhnnss'  == '20050309130856'
	
	Other examples - times:
	'hh:nn:ss AMPM'   == '13:08:56 PM' (The 13 and PM don't match.  You need the ap code before
	the hours - see next example)
	'aph:nn'          == '1:08' (is this am or pm?  missing placeholder ampm)
	'aphh:n:ss AMPM'  == '01:8:56 PM' (no leading zero on the minutes - not good)
	'aph:nnampm'      == '1:08pm' (no leading zero on hours and no space between minutes and pm)
	'aph:nn ampm'     == '1:08 pm' (no leading zero on hours - this looks much better)
	
	Other examples - preformated:
	'hm' or 'hn'      == '1:08' or '13:08' (= 'h:nn'. Need to use 'ampm' if you do not want 24 
							hour time.)
	'hms' or 'hns'    == '1:08:56' or '13:08:56' (= 'h:nn:ss'. Need to use 'ampm' if you do not 
							want 24 hour time.)
	'hmap' or 'aphn'  == '1:08 pm' (= 'aph:nn ampm')
	'hmsap' or 'aphns'== '1:08:56 pm' (= 'aph:nn:ss ampm')
	'mdy'             == 'March 9, 2005' (= 'mmmm d, yyyy')
	'dmdy'            == 'Tuesday, March 9, 2005' (= 'dddd, mmmm d, yyyy')
	'ymd'             == '2005.03.09' (= 'yyyy.mm.dd')
	
	Other examples - weird:
	'Today is dddd'   == 'To9ay i56 Tuesday' (What is going on? See next example).
	'To=day i=s dddd' == 'Today is Tuesday' (need = sign in front of d and s so they are treated
							as characters).
	'd dd ddd dddd'   == '9 09 Tue Tuesday'
	'm mm mmm mmmm'   == '3 03 Mar March'
	'mmmmmm'          == 'March03' (not '03March' nor 'MarMar' nor '333333' nor '303Mar' etc.)

	what does | do?  It signals the end of a token.  So mmmmmm


	Invalid Date Inputs:
	1999-03-09
	03091999
	----------------------------------------------------------------------------------------

	ap	 = flag to use 12 hour clock with AM or PM rather than 24 hour clock.  
			Set hours for ampm mode.  Restricts hours to less than 11 if code is used before hours 
			(e.g. before the h or hh or at the very begining of the format string).
	h	 =  0 - 23, hours.  If ap then 0-12, else 0-24.
	hh	 = 00 - 23, hours, two digit (add leading zeros where needed).  If ap then 00-12, else 00-24.

	n	 =  0 - 59, minutes (m is already taken by month number)
	nn	 = 00 - 59 (add leading zeros where needed), minutes, two digits
	s	 =  0 - 59, seconds
	ss	 = 00 - 59, seconds (add leading zeros where needed), two digits
	ampm = places am/pm
	ampmuc = places AM/PM (upper case)
	d    =  1 - 31
	dd   = 01 - 31 (leading zeros where needed)
	ddd  = Mon, ...
	dddd = Monday, ...
	w	 = Mon - Sun, week day name abbreviation, 3 characters
	ww	 = Monday - Sunday, week day full name.
	m	 =  1 - 12, month number
	mm	 = 01 - 12, month number, two digit
	mmm  = Jan - Dec, month abbreviation, 3 characters
	mmmm = January - December, month full name
	yy	 = 00 - 99 (add leading zeros where needed), year, last two digits
	yy   = 00 - 99 
	yyyy = 0000 - 9999
	
	Special or prebuilt codes:
	= is the default escape character.  Anything following an = will be displayed without interpetation 
		(e.g. if you want a 'd' you must use '=d' so the function does not convert the d to a date).
		The equal sign itself will not be displayed unless you use '=='.  You may override the escape
		character by passing a 3rd parameter (DELIM).  Don't use the vertical bar (|) as the delimiter.
	| is another special character.  It separates (or ends) tokens (or codes).  The code mmmmmm 
		will be broken into mmmm (longest possible match) followed by mm (January01).  If you want 
		to display JanJan then you must use mmm|mmm.  If you want to display a vertical bar (|) you
		must use =|.
	uc    = Uppercase everything flag (overrides ampm and ampmuc)
 	lc    = Lowercase everything flag (overrides ampm and ampmuc)
	hms   = h:mm:ss
	hmsap = aph:mm:ss ampm
	hm    = h:mm
	hmap  = aph:mm am/pm
	mdy   = mmmm d, yyyy
	dmdy  = dddd, mdy
	eur   = yyyymmdd
	eur-  = yyyy-mm-dd
	eur.  = yyyy.mm.dd
	ymd   = eur
	us    = m/d/yy
	usa   = m/d/yyyy

	*/

	debug ? alert('dateFormat : ' + dateToFormat +sep+ formatAs): '';
//d	alert('dateFormat : ' + dateToFormat +sep+ formatAs);
//d	if (dnum<DMAX) alert('dateFormat : ' + dateToFormat +SEP+ formatAs+SEP+dnum);
//d	dnum++;

	var aDate, pDate = new Date('1/1/2001'), oneChar, escapeChar = false, sReturn = '', token = '';

	if ((DELIM == 'undefined') || (DELIM == undefined) || (DELIM == '')) DELIM = '=';
//d	alert('dateFormat.b : ' + DELIM+sep);

	ampm = false;							// Reset global variable ampm to default status for each call to dateFormat().

	aDate = checkDate(dateToFormat);		// Convert dateToFormat to a date type if possible.
//d	alert(aDate);

	if (!aDate || aDate == 'Invalid Date')						// Verify aDate is a date type.
	{
//d		alert(aDate+sep+dateToFormat.toString()+sep+dateToFormat.length);
		if (dateToFormat.length == 8)							// Check for yyyymmdd format.
		{
			aDate = dateToFormat.toString();
			aDate = aDate.slice(4, 6)+'/'+aDate.slice(6, 8)+'/'+aDate.slice(0, 4); // Put in form mm/dd/yyyy.
//d			alert(aDate);
			return dateFormat(aDate, formatAs);			// Recall function with acceptable date format.
		}
		else if (dateToFormat.length == 4)							// Check for mmdd format.
		{
			aDate = dateToFormat.toString();
			aDate = aDate.slice(0, 2)+'/'+aDate.slice(2, 4)+'/'+dateFormat(new Date(), 'yyyy'); // Put in form mm/dd/yyyy.
//d			alert(aDate);
			return dateFormat(aDate, formatAs);			// Recall function with acceptable date format.
		}
		else if (dateToFormat.length == 0)						// Check for the empty string.
		{
			return '';
		}
		else
		{
			return '**dateFormat error: -'+dateToFormat+'- is not a date.**';		// dateToFormat is not in a date form.
		}
	} 

//c	formatAs = formatAs.toLowerCase();	// can't do here in case user wants some upper case letters in format string.

	do	// parse formatAs finding tokens and building sReturn string.
	{
		oneChar = formatAs.slice(0, 1);		// Get first 1 character(s) of format string.
		formatAs = formatAs.slice(1);		// remove first 1 character(s) from format string.
//d		alert(oneChar +sep+ formatAs +sep+ token); //d

		if (escapeChar)							// Just in case '...=' (nothing after an equal sign).
		{
			sReturn += oneChar;				// flush the buffer.
//d			alert('esc char = '+sReturn);
			escapeChar = false;
			continue;
		}
		
		if (isTokenPart(dateTokens, token+oneChar))	// Check if existing characters in token plus new character
		{											//  is still part of a token.
			token += oneChar;
//d			alert('building possible token = '+token);
		}
		else	// the new character is not part of the existing token.
		{
			if (token == '')	// nothing in token and new char does not start a token.
			{
				if (oneChar == DELIM)	// is new char the delimiter?
				{
					escapeChar = true;		// just set the flag.  This handles '...=' (nothing after an equal sign).
				}
				else
				{
					if (oneChar != TOE)					// Loose TOE.
					{
//c						if (oneChar == " ")				// if a space
//c						{
//c							sReturn += "&nbsp;";		// then replace with a hard space.
//c						}
//c						else
//c						{
							sReturn += oneChar;
//c						}
					}
//d					alert('sReturn single char = '+sReturn);
				}
			}
			else	// we have a token, or the starting characters of a token, and a character.
			{
				if (isToken(dateTokens, token))								// whole token?
				{
					sReturn += convertDateToken(aDate, token);	// process token.
					token = '';									// reset token.
					if (oneChar != TOE)					// Loose TOE.
					{
						formatAs = oneChar + formatAs;	// place back the character.
					}
//d					alert('whole token = '+sReturn);	//d
				}
				else										// partial token but no match
				{
					formatAs = token + oneChar + formatAs;		// place back the characters of partial token
					token = '';
					oneChar = formatAs.slice(0, 1);		// Get first 1 character(s).
					formatAs = formatAs.slice(1);		// remove first 1 character(s) from string.
					if (oneChar != TOE)					// Loose TOE.
					{
						sReturn += oneChar;
					}
//d					alert('partial token = '+sReturn);	//d
				}
			}
//d			alert('formatAs = '+formatAs);	//d
		}
		
	} while (formatAs != '');
	
	if (token != '')								// in case format string ends with token or token part.
	{
//d		alert("Token is :"+token+":");
		if (isToken(dateTokens, token))
		{
			sReturn += convertDateToken(aDate, token);	// add full token left over.
		}
		else
		{
			sReturn += token;						// add partial token left over.
		}
		token = '';
	}
//d	alert('********sReturn7 = ' + sReturn);

	if (upperCase)
	{
		sReturn = sReturn.toUpperCase();
	}
//d	alert('********sReturn9 = ' + sReturn);
	
	if (lowerCase)
	{
		sReturn = sReturn.toLowerCase();
	}

//d	alert('********sReturn10 = ' + sReturn);

	return sReturn;
	
} // end dateFormat().


/*
var Today    = new Date();
var Seconds  = Today.getSeconds();
var Minutes  = Today.getMinutes();
var Hours24  = Today.getHours();
var DayoMnum = Today.getDate();
var DayoWnum = Today.getDay();
var Monthnum = Today.getMonth() + 1;
var Year     = Today.getFullYear();
var MSTime   = Today.getTime();			// Milliseconds since Dec 31, 1969 at 6pm.
var DaysLeft = XmasDays(Today);
var MonthName = getMonthName(Monthnum, 0);
var DayName  = GetWeekDayName(DayoWnum, 0);
var Timeampm = getHMMSSampm(Hours24, Minutes, Seconds);
alert('datetime.js: ' + 'Today is '+ Timeampm +'.'+Today.getMilliseconds());

var output = "Today is ";
output += DayName + ", ";
output += MonthName + " ";
output += DayoMnum + ", ";
output += Year;
output += " at ";
output += (Hours24 > 12) ? Hours24 - 12 : (Hours24 == 0) ? "12" : Hours24;
output += ":";
output += (Minutes > 9)  ? Minutes : "0" + Minutes;
output += ":";
output += (Seconds > 9)  ? Seconds : "0" + Seconds;
output += (Hours24 > 11) ? "PM" : "AM"

document.write(output, "<br />");
*/
//d	alert('datetime.js: end');

