/* ***********************************************************
** TIMEDATE.JS - JS Time/Date-Processing Library
** =============================================
** This library contains functions to process time and date
** values. It's yours for free; please maintain this header!
**
** To load this library in an HTML doc, put the following
** line in the doc's HEAD (before any other SCRIPT tags):
**
** <SCRIPT SRC="timedate.js" LANGUAGE="JavaScript"></SCRIPT>
**
** Author      Ver  Date    Comments
** ======      ===  ====    ========
** Rick Scott  1.0  1/1/00  First release
**
** Copyright 2000, Rick Scott, all rights reserved.
*********************************************************** */

/* ***********************************************************
** USAGE
** =====
** var myDate1 = new TimeDate()
**   creates a TimeDate object named myDate1, time/date = now
** var myDate2 = new TimeDate("dateString")
**   creates TimeDate obj named myDate2, date = dateString vals
**   dateString format: "Month day#, yyyyYear#"
**   for example: "January 1, 2000" 
** all TimeDate objects have the following properties:
**   objName.date - date (in default JS format)
**   objName.year - year (in yyyy format)
**   objName.monthNum - month number (1-12)
**   objName.zp_monthNum - zero-padded month num (01-09)
**   objName.monthName - month name ("January", etc.)
**   objName.dayNum - day number (1-31)
**   objName.dayNumSuffix - // day-num suffix (st, nd, rd, etc.)
**   objName.zp_dayNum - zero-padded day num (01-09)
**   objName.dayName - day name ("Sunday", etc.)
**   objName.hours - hour number (0-23)
**   objName.zp_hours - zero-padded hour num (00-09)
**   objName.ampmhours - am/pm hour number (1-12)
**   objName.ampm - am or pm?
**   objName.minutes - minute number (0-59)
**   objName.zp_minutes - zero-padded minute num (00-09)
**   objName.seconds - second number (0-59)
**   objName.zp_seconds - zero-padded second num (00-09)
**   objName.msecs - num milliseconds in date
**
** get_duration(startDate, endDate, timeUnits)
**   calcs duration in timeUnits between startDate and endDate
**   startDate - any valid TimeDate object
**   endDate - any valid TimeDate object
**   timeUnits - SECONDS, MINUTES, HOURS, DAYS, WEEKS, 
**     MONTHS, YEARS
*********************************************************** */

// global duration constants
var MSECSINSECOND = 1000;
var MSECSINMINUTE = 1000 * 60;
var MSECSINHOUR   = 1000 * 60 * 60;
var MSECSINDAY    = 1000 * 60 * 60 * 24;
var MSECSINWEEK   = 1000 * 60 * 60 * 24 * (365.25/52);
var MSECSINMONTH  = 1000 * 60 * 60 * 24 * (365.25/12);
var MSECSINYEAR   = 1000 * 60 * 60 * 24 * 365.25;
var SECONDS       = "seconds";
var MINUTES       = "minutes"; 
var HOURS         = "hours";
var DAYS          = "days";
var WEEKS         = "weeks";
var MONTHS        = "months";
var YEARS         = "years";

// store month names in monthNames array
var MonthNames = new Array("January", "February", "March", "April", "May",
    "June", "July", "August", "September", "October", "November", "December");

// store day names in dayNames array
var DayNames = new Array("Sunday", "Monday", "Tuesday", "Wednesday", 
    "Thursday", "Friday", "Saturday");

function TimeDate(dateStr)  // TimeDate object constructor function
  {
  if (arguments.length > 1)   // new TimeDate(year, month, etc.) calls illegal!
    return;
  if (arguments.length == 0)  // handle call: new TimeDate()
    this.date = new Date();
  else                        // handle call: new TimeDate(dateStr)
    this.date = new Date(dateStr);
  this.year = get_year(this.date);               // year (in yyyy format)
  this.monthNum = this.date.getMonth() + 1;      // month number (1-12)
  this.zp_monthNum = zeropad(this.monthNum);     // zero-padded month num (01-09)
  this.monthName = MonthNames[this.monthNum-1];  // month name ("January", etc.)
  this.dayNum = this.date.getDate();             // day number (1-31)
  // day-num suffix (st, nd, rd, etc.) - to create strings: 1st, 2nd, 3rd, etc.
  this.dayNumSuffix = get_dayNumSuffix(this.dayNum);
  this.zp_dayNum = zeropad(this.dayNum);         // zero-padded day num (01-09)
  this.dayName = DayNames[this.date.getDay()];   // day name ("Sunday", etc.)
  this.hours = this.date.getHours();             // hour number (0-23)
  this.zp_hours = zeropad(this.hours);           // zero-padded hour num (00-09)
  this.ampmhours = get_ampmHours(this.hours);    // am/pm hour number (1-12)
  this.ampm = get_ampm(this.hours);              // am or pm?
  this.minutes = this.date.getMinutes();         // minute number (0-59)
  this.zp_minutes = zeropad(this.minutes);       // zero-padded minute num (00-09)
  this.seconds = this.date.getSeconds();         // second number (0-59)
  this.zp_seconds = zeropad(this.seconds);       // zero-padded second num (00-09)
  this.msecs = this.date.getTime();              // date in milliseconds
  }

// calculate the duration in timeUnits between startDate and endDate
function get_duration(startDate, endDate, timeUnits)
  {
  var divisor;

  duration = endDate.msecs - startDate.msecs;
  if (timeUnits == YEARS)
    divisor = MSECSINYEAR;
  else if (timeUnits == MONTHS)
    divisor = MSECSINMONTH;
  else if (timeUnits == WEEKS)
    divisor = MSECSINWEEK;
  else if (timeUnits == DAYS)
    divisor = MSECSINDAY;
  else if (timeUnits == HOURS)
    divisor = MSECSINHOUR;
  else if (timeUnits == MINUTES)
    divisor = MSECSINMINUTE;
  else if (timeUnits == SECONDS)
    divisor = MSECSINSECOND;

  var returnVal = duration/divisor;
  if (returnVal >= 0)
    return Math.floor(duration/divisor);
  else
    return Math.ceil(duration/divisor);
  }

function get_year(date)  // get year in  format (e.g., 2000, not 0 or 100)
  {
  var year = date.getYear();
  if (year < 1000)
    year += 1900;
  return year;
  }

function get_ampmHours(hournum) // convert hour num for am/pm
  {
  if (hournum == 0)   // 12 am
    return 12;
  if (hournum > 12)   // 1-12 (pm)
    return (hournum - 12);
  else                // 1-11 (am)
    return hournum;
  }

function get_ampm(hournum)  // return "am" or "pm" string
  {
  if (hournum < 12)
    return "am";
  else
    return "pm";
  }

function zeropad(num)  // zero-pad single-digit numbers (00...09)
  {
  if (num < 10)
    return ("0" + num);
  else
    return num;
  }

function get_dayNumSuffix(num)  // return day-num suffix (1st, 2nd, 3rd, ..., 31st)
  {
  if (num == 1 || num == 21 || num == 31)
    return "st";
  else if (num == 2 || num == 22)
    return "nd";
  else if (num == 3 || num == 23)
    return "rd";
  else
    return "th";
  }
