Hamlet, Act 2 scene 2 (Oh how I hate Daylight Savings, TimeZones, and the fact XML can’t deliver a date format JavaScript understands)

 Yes, while working onsite at a Client’s place I’ve been getting my hands all icky with code… I scrub and I scrub but all of the ocean’s waters won’t wash this code from my hands.

Anyway, the point of this blog entry is to record the challenge that I had and the code I wrote to fix it, as it will be useful in the future for both me and maybe others. Essentially, the page I was fixing was giving me times in Zulu (GMT) – and in an XML format the JavaScript time functions could not understand. The business requirement was to have the times appear in Outlook in the same time zone the user was using. It took me the better part of a day, and I learned way too much about time zones and how to detect them on the user’s computer, but I got there in the end.

The original code for this was here – http://patrikluca.blogspot.com/2008/03/extension-to-rooms-and-equipment.html – an "Add to Outlook" button to go beside every Resource reservation, for a company still using a Lotus Notes app that allowed them to place multiple conflicting (overlapping) bookings on the same room / item.

I leveraged the free "Resource Reservation" add-in for SharePoint and enhanced it according to the article, but when the users started using it they noticed that the times never matched. It was always 10 hours earlier than the real booking time that appeared in the page. Hmmm… 10 hours… Australia’s GMT+10, so it must be passing them in as GMT Times.

I updated the JavaScript so the times were changed back to the equivalent time zone (taking into account daylight savings) of the current user (Useful because this client is in 4 different time zones at any time as a minimum). There’s only one problem in the code (and it’s unlikely to be hit) but if a user books a resource for either side of a daylight savings change, then one of the times will be out by 1 hour. You can see the note I’ve put in there to remind myself if I ever get asked to fix it 🙂

If you are copying the code, watch out for line breaks!


function createOutlookAppointment(title,meetinglocation,startdate,enddate)    
{
// if you ever get asked to manage the booking hours over a DST change period, you will need to
// test each date to see if it is in dst – isDST returns 1 if it is during DST, and 0 if not
// if (isDST(startdate) – isDST(enddate)) = -1 then the end time is during DST
// if (isDST(startdate) – isDST(enddate)) = 1 then the start time is during DST
// however if the calculation = 0 then leave ’em be
//   newAppt = new appt(title, meetinglocation, formatIncomingDateTime(startdate + ‘_’ + isDST(startdate)), formatIncomingDateTime(enddate) + ‘_’ + isDST(enddate));
   newAppt = new appt(title, meetinglocation, formatIncomingDateTime(startdate), formatIncomingDateTime(enddate));

  saveAppt( newAppt );
}

function isDST(incomingDateTime)
{
// This function detects if the inbound date and time is in Daylight savings time, and returns a 1 if it is, and a 0 if it’s not
// Kinda handy, seeing as DST is always "1" hour difference
//I’ve dropped this in so I don’t have to find it again if I ever do need to fix it
  var yearPart = incomingDateTime.substring(0,4);
  var monthPart = incomingDateTime.substring(5,7);
  var dayPart = incomingDateTime.substring(8,10);
  var d = new Date(yearPart, monthPart, dayPart);
//   var d=new Date();
   var dY=d.getFullYear();
   var d1=new Date(dY,0,1,0,0,0,0);   
   var d2=new Date(dY,6,1,0,0,0,0);  
   var d1a=new Date((d1.toUTCString()).replace(" GMT",""));  
   var d2a=new Date((d2.toUTCString()).replace(" GMT",""));  
   var o1=(d1-d1a)/3600000;  
   var o2=(d2-d2a)/3600000;  
   var rV=0;  
   if (o1!=o2)
   {   
     d.setHours(0);
     d.setMinutes(0);
     d.setSeconds(0);
     d.setMilliseconds(0); 
     var da=new Date((d.toUTCString()).replace(" GMT",""));
     o3=(d-da)/3600000;   
     rV=(o3==o1)?0:1;  
    }
  return rV;
}

function formatIncomingDateTime(incomingDateTime){

  var timePartHours = incomingDateTime.substring(11,13);
  var timePartMinSecs = incomingDateTime.substring(13,16);
  var yearPart = incomingDateTime.substring(0,4);
  var monthPart = incomingDateTime.substring(5,7);
  var dayPart = incomingDateTime.substring(8,10);
  var newDate = new Date(yearPart, monthPart, dayPart); //gives us the current date and time in UTC
  var timeOffset = (newDate.getTimezoneOffset())/60; //gives us the amount of hours we need to deduct

  //create the date we are going to manipulate
  var myDate = new Date(yearPart, monthPart, dayPart);

  //calculate the hour we are booking for…
  timePartHoursInt = parseInt(timePartHours,10) – timeOffset;

  if (timePartHoursInt < 0) {
   //This means the booking hours + the time offset are really for yesterday…
   //because the timeoffset is the difference between current local time and GMT
   //so a negative number means we need to deduct a day and change it into real time again by adding 24h
   timePartHoursInt += 24;
   myDate.setDate(myDate.getDate() – 1);
  }
  else if (timePartHoursInt >= 24) {
   //in this case, we are booking for tomorrow (and midnight – 00:00:00 – is tomorrow)
   timePartHoursInt -= 24;
   myDate.setDate(myDate.getDate() + 1);
  }

if (timePartHoursInt < 10) {
// add a leading 0 to the time string so it’s formatted in a standard way
// then convert the int to a string
  timePartHours = ‘0’+timePartHoursInt.toString();
}
else {
  timePartHours = timePartHoursInt.toString();
}

  if (myDate.getMonth() < 10)
// add a leading 0 to the time string so it’s formatted in a standard way
// then convert the int to a string
   monthPart = ‘0’+myDate.getMonth();
  else
    monthPart = myDate.getMonth();

  if (myDate.getDate() < 10)
// add a leading 0 to the time string so it’s formatted in a standard way
// then convert the int to a string
    dayPart = ‘0’+myDate.getDate();
  else
    dayPart = myDate.getDate();

  var datePart = myDate.getYear() + ‘-‘ + monthPart + ‘-‘ + dayPart;

  return datePart.concat(‘ ‘.concat(timePartHours).concat(timePartMinSecs));
}

function appt( Subject, Location, Start, End){

  this.Subject = Subject;
  this.Location = Location;
  this.Start = Start;
  this.End = End;

  this.ReminderMinutesBeforeStart = 15;
}
function saveAppt( obj ){

  var olAppointmentItem = 1;

  out = new ActiveXObject( "Outlook.Application" );

  appt = out.CreateItem( olAppointmentItem );

  appt.Subject = obj.Subject;
  appt.Location = obj.Location;
  appt.Start = obj.Start;
  appt.End = obj.End;

  appt.ReminderMinutesBeforeStart = obj.ReminderMinutesBeforeStart;         

  appt.Display();
  return null;
}      


This "Add to Outlook" button can be used on any page that can pass in a Start and End date, time, a Title (for the calendar appointment) and a location (eg a calendaring Confluence site?). With a bit of modification you could also add other attendees, a reminder, etc.

However, the site hosting the link / button must be trusted for this to work properly. If the site appears in the "Internet Zone" you just get a JavaScript error. If your site sits in the Intranet security zone you get a security dialogue, asking you if you are sure you want to run this crazy activeX control.

Anyway, an interesting day and a successful outcome for the client.Although a word of warning – the Room and Resource Reservation solution from Microsoft will deploy successfully on a Publishing website, however it will NOT stop users from booking an overlapping meeting (because there’s a conflicting named column or content type – one or the other).

Brad

Advertisements

About Brad Saide

I'm a SharePoint consultant. I'm also slowly going bald, seem to have a permanent spare tyre around my waist and enjoy socialising with friends over a beer or 10. The last 2 may possibly be related. Started working with SharePoint when the first version was in limited beta release (participated in the Technology Adoption Program while at Woolworths) and have been committed to the adoption of the technology as a business enabler ever since.
This entry was posted in Uncategorized. Bookmark the permalink.

One Response to Hamlet, Act 2 scene 2 (Oh how I hate Daylight Savings, TimeZones, and the fact XML can’t deliver a date format JavaScript understands)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s