// page clocks

/*
*** *** *** Daylight Saving Time *** *** ***
- SPRING ("spring forward"): 
	In spring, we set our clocks forward one hour ahead of standard time 
- FALL/AUTUMN ("fall back"):
	We "fall back" in autumn by setting our clock back one hour and thus returning to standard time
----------------------------------------------------------------
* EXAMPLE: Heidelberg, Belgrade... *
* - SPRING: At 2 a.m. on the LAST Sunday in March, go forward one hour (+1)
* - FALL/AUTUMN: At 2 a.m. on the LAST Sunday in October, set clock back one hour
----------------------------------------------------------------
*/

/* info for Daylight Saving Time (DST) in Toronto:
	- for spring: At 2 a.m. on the SECOND Sunday in March, go forward one hour 
	- for autumn: At 3 a.m. on the FIRST Sunday in November, set clock back to standard time  */
var Toronto_DST_info = {"div_tag_id" : "tP", "offset" : -5, "spring" : Array ("Mar","Sun",2, 2,0,0), "autumn" : Array ("Nov","Sun",1, 3,0,0)}; 
/* info for Daylight Saving Time (DST) in Heidelberg, Belgrade...:
	- for spring: At 2 a.m. on the LAST Sunday in March, go forward one hour; 
	- for autumn: At 3 a.m. on the LAST Sunday in October, set clock back to standard time  */
var Heidelberg_DST_info = {"div_tag_id" : "tC", "offset" : 1, "spring" : Array ("Apr","Sun",0, 2,0,0), "autumn" : Array ("Nov","Sun",0, 3,0,0)}; 

var page_clocks = Array (Toronto_DST_info, Heidelberg_DST_info);

/* E.g. If clock should be switched to new time due to Daylight Saving Time on SECOND Sunday in March, then this function calculates what date is this day 
(for example, March 8th 2009 is the second Sunday in March 2009, March 11th 2007 is the second Sunday in March 2007, etc.). 
The time parameters are expected to be by standard time (e.g. if clock is to be set back to standard time in autumn at 3 AM, then this is 3 AM current time (forwarded for 1 hour) but 2 AM by standard tme. */
function getDSTSwitchDate(sd_year, sd_month, sd_weekday, sd_weekday_ordinal, sd_h, sd_m, sd_s) {
	var months = "|JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC|";
	sd_month = "|" + sd_month.toUpperCase() + "|";
	var month_index = months.indexOf(sd_month) / 4; //equals 0 for January, 1 for February, etc.
	var weekdays = "|SUN|MON|TUE|WED|THU|FRI|SAT|";
	sd_weekday = "|" + sd_weekday.toUpperCase() + "|";
	var weekday_index = weekdays.indexOf(sd_weekday) / 4; //equals 0 for Sunday, 1 for Monday, etc.
	var i = 1;
	var d = new Date(sd_year, month_index, 1, sd_h, sd_m, sd_s); //first day in requested month and year
	
	if (weekday_index < 0) return;
	if (month_index < 0) return;
	
	//search for 1st weekday in specified month and year, e.g. if we need 2nd Sunday, then we search which day in a first week is Sunday
	while ((d.getDay() != weekday_index) && (i<8)) { 
		d = new Date(d.getFullYear(),d.getMonth(),d.getDate()+1, sd_h, sd_m, sd_s);
		i++;
	}
	
	//Go to n-th weekday (sd_weekday_ordinal) in requested month and year i.e. find switch date (sd); 
	//e.g.1. for FIRST Sunday in Nov, set 1 for sd_weekday_ordinal and Nov for sd_month
	//e.g.2. for LAST Sunday in Oct, set 0 for sd_weekday_ordinal and Nov for sd_month
	sd = new Date(d.getFullYear(),d.getMonth(),d.getDate()+7*(sd_weekday_ordinal-1), sd_h, sd_m, sd_s);
	
	//if (  (sd.getMonth() != d.getMonth())  &&  (sd_weekday_ordinal > 0)  ) sd = d; <-- uncomment this if you want to return 1st weekday in current month in case sd becomes a date in a following month 
	
	return sd;
}

//This function returns current date for requested city respecting DST
function tDST(info) {
	var time_offset;
	var cur_date = tN();
	var x = new Date(cur_date.getUTCFullYear(),cur_date.getUTCMonth(),cur_date.getUTCDate(),cur_date.getUTCHours(),cur_date.getUTCMinutes(),cur_date.getUTCSeconds());
	//UTC time: The Universal Coordinated Time (UTC) is the time set by the World Time Standard.
	//IMPORTANT: UTC time returned by JS is based on user's computer so if user does not have his/her date and time set correctly, this UTC time will not be correct!
	
	var standard_time_offset = info["offset"]; //e.g. Toronto's standard time is [UTC time  -  5 hours]
	var standard_time = new Date();
	standard_time.setTime(x.getTime() + standard_time_offset*60*60*1000);
	
	//getDSTSwitchDate() parameters: getDSTSwitchDate(sd_year, sd_month, sd_weekday, sd_weekday_ordinal, sd_h, sd_m, sd_s)
	//info[spring/autumn]: Array (month,weekday name,ordinal of weekday, hour,minute,second), e.g. Array ("Mar","Sun",2, 2,0,0)
	var switch_time_spring = getDSTSwitchDate(x.getUTCFullYear(),info["spring"][0],info["spring"][1],info["spring"][2],info["spring"][3],info["spring"][4],info["spring"][5]); //e.g. for Toronto: 2 AM on second Sunday in March
	var switch_time_autumn = getDSTSwitchDate(x.getUTCFullYear(),info["autumn"][0],info["autumn"][1],info["autumn"][2],info["autumn"][3]-1,info["autumn"][4],info["autumn"][5]); //e.g. for Toronto: 3 AM current time on first Sunday in November
	
	//check if the time needs to be set forward for 1 hour
	if ((standard_time > switch_time_spring) && (standard_time < switch_time_autumn)) {
		time_offset = standard_time_offset + 1; //set clock forward 1 hour ahead of standard time 
	} else {
		time_offset = standard_time_offset; //use standard time offset
	}
	
	x.setTime(x.getTime() + time_offset*60*60*1000);
	
	return x;
} 

function tN(){ return new Date(); } 
function lZ(x){ return (x>9)?x:'0'+x; } 
function tH(x){ if(x==0){ x=12; } return (x>12)?x-=12:x; } 
function aP(x){ return (x>11)?'pm':'am'; } 

var date_to_show = "' '+tH(tDST(info).getHours())+':'+lZ(tDST(info).getMinutes())+':'+lZ(tDST(info).getSeconds())+' '+aP(tDST(info).getHours())";;
function runClock(ind){
	info = page_clocks[ind-1];
	document.getElementById(info["div_tag_id"]).innerHTML = eval(date_to_show); 
	setTimeout("runClock("+ind+")",1000); 
} 

//start clocks
function runClocks() {
	runClock(1); //Toronto
	runClock(2); //Heidelberg, Belgrade...
}

runClocks();
