Adam Howitt's Blog

Sep 19
2009

Working with Dates and Date offsets in iPhone Development

It's been a slow iPhone development week partly because I'm in the peak week of my marathon training but the main reason is that the work I did was pretty frustrating so it put me off doing more until today.

When is a date not a date?

When it's a datetime, silly. Working with dates in iPhone means you work with the misleading named class NSDate which not only stores a date and a time but the timezone data too. That little caveat aside I can dive into my issue dujour.

I'm building a UITableView where the groups are the week numbers and the cells are the days within those weeks calculated from a start date for the whole table. So if the start date is Monday September 21st 2009, the first section header is "week 1" and the first cell is Monday September 21st 2009.

The week section is easy to calculate:

NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSUInteger currentWeek = section+1;

Next up is the calculation for the first cell. It should be easy right? The first cell of week 1 represents 0 weeks after the start date for the tableview and 0 days after the start, so our formula for dayOffset:

NSUInteger dayOffset = (section-1)*7+rows;

So day 1 of week 1 has a dayOffset of 0, day 1 of week 2 has a dayOffset of 7 etc. All that remains is to add the dayOffset to my startDate and I've got the date for the cell.

The challenge isn't finishing - starting is the hardest part

Working with an NSDate object my first instinct was to look at the NSDate class and find a function to add a set number of days to a date and found that there is only the function addTimeInterval:
- (id)addTimeInterval:(NSTimeInterval)seconds;
That's seconds for those of you who missed the nuance. So it appears I have to turn my dayOffsets into seconds before I can add them to a start date. Fine.
NSUInteger secondsOffset = dayOffset*24*60*60;

First a quick side-bar. As I mentioned earlier, I'm passing in a date, not a date time so I set my date formatter object to parse MM/dd/yy dates (where MM is 2 digit month vs mm which is 2 digit minutes).

NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:@"MM/dd/yy"];
NSDate *frDate = [df dateFromString:[tableSourceFile objectForKey:@"startDate"]];
NSLog(@"%@",[frDate description]);
The NSLog confirms that my date "09/21/09" has now become "2009-09-21 00:00:00 -0500". This seems like a reasonable summary, I guess :-)

I added my dayOffset to my date:

NSDate *cellDate = [frDate addTimeInterval:secondsOffset];
and then as I drag down through my UITableView I see it all unfold perfectly. Wait. Everything is fine but on Sunday November 1st 2009 instead of ticking over in Week 7 Day 1 to Monday November 2nd 2009 I get Sunday November 1st 2009 again. WTF?

I'm a little embarrassed at the hour and a half of bashing my head against this, double checking my start date, my logic, my days to seconds calculations, NSLogging out every variable involved to the log. It seems the first November 1st is "2009-11-01 00:00:00 -0500" and the second is "2009-11-01 23:00:00 -0600". A timezone switch? I plead late night development insanity on this but eagle-eyed wide-awake super-designer Jeff spots that it's not a change in timezone but the change in daylight savings time.

So turning days into seconds becomes nuts if you cross DST boundaries. To workaround this I have the bright idea to pass in noon as part of my start date because if the date shifts by 1 hour either way it still remains the same day:

NSDateFormatter *df = [[NSDateFormatter alloc] init];
//Change dateformatter to look for time
[df setDateFormat:@"MM/dd/yy HH:mm"];
NSDate *frDate = [df dateFromString:[tableSourceFile objectForKey:@"startDate"]];
//Correctly writes out "2009-09-21 12:00:00 -0500"
NSLog(@"%@",[frDate description]);
//Now do the addition:
NSDate *cellDate = [frDate addTimeInterval:secondsOffset];

I've created... a monster!

It works! By setting the time as noon I've got it working but I have a nagging feeling I'm missing something obviously simpler. It's close to midnight so I wrap up and leave for the night kicking myself for missing the obvious.

The next morning I pull up the docs and start digging around again looking in forums for date manipulations. I'm not sure of the exact path to enlightenment but I find the "Date and Time Programming Guide for Cocoa" and, more importantly, the section "Calendrical Calculations".

It *appears* that by using NSDateComponents to build an offset and NSCalendar to specify a basis for the calculations I can add the offset in days to a date based on the gregorian calendar. Since I'm adding days not seconds I wonder if this will avoid the issue I jammed thru.

Pressure creates diamonds

I didn't have time until this morning to test my theory so I sat down and plugged at it earlier.
//Create my dateformatter object
NSDateFormatter *df = [[NSDateFormatter alloc] init];
//Change dateformatter back to date only
[df setDateFormat:@"MM/dd/yy"];
NSDate *frDate = [df dateFromString:[tableSourceFile objectForKey:@"startDate"]];
//NSLog confirms my date"2009-09-21 00:00:00 -0500"
NSLog(@"%@",[frDate description]);
//Create an offset object
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
//Pass in our offset in days
[offsetComponents setDay:(section*7)+row];
//Select a calendar for the calculations
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
//With the gregorian calendar add my offset object to the start date
NSDate *cellDate = [gregorian dateByAddingComponents:offsetComponents toDate:frDate options:0];
//Release the offset and the calendar
[offsetComponents release];
[gregorian release];
Week 1 Day looks fine and dandy "2009-09-21 00:00:00 -0500", what about the mysterious DST cutover on Week 6 day 7? "2009-11-01 00:00:00 -0500" and then Week 7 Day 1: "2009-11-02 00:00:00 -0600". It behaves the way I expected so when I output my date to the UITableViewCell textLabel I get the day and can ignore the time:
//Display 3 character day of week, 2 digit day and 3 character month e.g. Mon, 21 Sep
[df setDateFormat:@"EEE, dd MMM"];
cell.textLabel.text = [edf stringFromDate:today];
Voila. 3 hours of development time to add a number of days to a date because my first instinct was such a wild goose chase. I've emailed the iPhone docs team to let them know that it would be great to add the link to the section on "Calendar Calculations" to the addTimeInterval method detail since, IMHO, it's the first place a new iPhone/cocoa developer would think to look.

I hope this helps someone else dodge the bullet and let me know if there are typos/errors/omissions in the code since typing in anger like this rarely reproduces perfect code! Have a great weekend.

Jan 17
2009

BlogCFC 5.9.2.002 Live and Kicking

I've finally upgraded WebDevRef to use BlogCFC 5.9.2.002 so hopefully any commenters or readers who have suffered from the spammers attacking my blog lately will have an extra line of defense.

This was quite painful as a move because I've skipped about 3 major versions and 6 point releases and the database changed drastically. Not to mention the fact that I have a custom design from Jeff that took the best part of today to reintegrate. I hope this is as much use to everyone else as it will be to me.

I've also decided to remove the $5 archive fee - it was a useful experiment and drew some very passionate responses. In 3 months I sold 3 blog entries but it wasn't really about that.

As I've been working for myself this past year I've been struggling to make the time to blog about my CF adventures and justify the time. I felt like I needed a sign that someone thought it was worth the effort I put in. I thought $5 per article would give me that validation but it seems I was a little misguided :-) I've spent a lot of time soul searching and realized that I get a lot of satisfaction just from taking the time to write. So I'm back and ready to blog with some brand spanking new blog features. Thanks to Ray Camden as ever for continuing to lead the development of BlogCFC.

Dec 03
2008

Seth Godin says my seminar is a lost cause

Well, close.  Jeff just sent me an article from Seth's blog pointing out that marketing evolution is much harder than marketing gravity because gravity is something people already believe in.

I'm banking on people believing that evolving your website is cheaper and more productive than starting from scratch or paying for AdWords campaigns.  

The seminar follows a logical flow from fixing the problems for the visitors you get before chasing new visitors with SEO and AdWords campaigns.

The morning shows you how to use Google Analytics to analyze the traffic you get to find the problems on your website.  Next I'll cover Google Website Optimizer to help you split test a theory without fighting with the CEO over what goes on the home page.

The afternoon starts with Search Engine Optimization basics to make sure you're getting the best free traffic possible before you invest in pay-per-click, the focus of the last session of the day.  Google AdWords can be expensive if the material covered in the first 3 sessions isn't addressed and I'll teach you how to change the way you buy your campaigns to get the most for your dollar.

The first one day seminar is December 17th in Chicago and space is restricted to a cozy crowd of 10 to promote interaction and make sure everyone goes home with a personal action plan.  If you can't make it to Chicago for the day, let me know if you think there is a demand for the seminar in your city.

Sign up now for Website Evolution!

Feb 25
2008

WalkJogRun on Air

The clock is ticking.  In what I hope will be next to no time, I expect to be announcing the launch of a new Flex 3 version of WalkJogRun.net in the next couple of weeks and an offline AIR version a couple of weeks later.  Adobe just launched AIR 1.0 and Flex 3 so Jeff and I have jumped into it. Watch this space and in the meantime, go for a run.

Sep 26
2007

AdamHowitt.com launched

I know, two launch posts in one month but this one is THE most significant for me in that it marks the launch of my solo career as a consultant.  The beautiful design of Adam Howitt Consulting is the handywork of my former colleague and good buddy Jeff Kenny. He always amazes me when he pulls this stuff together.

The site features

  • Hcard integration on the contact page through technorati's hcard to vcard converter
  • CSS layouts including a print style sheet for the printable scoop
  • Google Analytics with Goal Configuration to track conversions, referers, vcard downloads and page effectiveness

My elevator pitch is that I'm offering website management, not website development.  I feel like the market for web developers is saturated and the price of a truly skilled developer has become commoditized.  Instead I'll be focussing on two separate angles targetted at marketers and developers:

  1. Campaign management - tracking and optimizing both online and offline ad campaigns
  2. Content management - tracking, optimizing and tuning your website content
  3. Traffic management - load testing, application troubleshooting and performance tuning
So if you have a problem, if no one else can help and if you can find him, maybe you can hire the a-team.

Jul 13
2007

Hotmail spam blocker

I did my first newsletter mailing today to the 6,000 members who opted in over the last year to WalkJogRun for infrequent email updates and I've got to tell you - it was a blast! I wrote the content and Jeff put together a design for the format, correcting a few things here and there. We used Campaign Monitor to send the messages and the tools are perfect. I uploaded a CSV list from my database of the opt-in members while Jeff uploaded the HTML and ran a few tests to make sure his semantic markup looked good in a range of email clients. They currently charge $5 base cost plus one cent per email so it cost us just over $65 for the list. At 1pm CST 6,000 WalkJogRun members emails were on their way and we had 5 mins to wait before the stats started to come in.

The first response of course is all the bounces from mail servers around the world declaring hard and soft bounces for their domains. Next was a swarm of Out of Office replies in the reply to email address box. Some of these were "I'll be out of the office until..." but some were "I'll be out of the office - forever! I no longer work at ...". Some of these were really funny to read, others straightforward. Being obsessive about things like this, every 15 minutes I would hit refresh to see the open rate and clickthrough rate climbing. As it stands at 2pm (26 hours into the mailing) there have been 1,729 unique opens and a 486 clickthroughs to the site or the articles, 34 people have unsubscribed and 176 emails bounced (101 hard). The reports give you a great overview of the campaign progress to date and allow you to drill down to view opens over time, unsubscribes over time, link activity and plenty more.

My only concern is that we are 30% deep into the open rate with 0.26% spam reports. On further investigation, all but one of the spam reports are from hotmail accounts. I'm very familiar with their process for spam having witnessed my wife innocently configuring her email. I'm not sure if it's a default setup but her email is set to only receive mail from people in her address book. All other mail goes to the spam trap. Every few days she looks in the spam trap and reads messages in place, transfers some to her inbox and just outright deletes others. The majority of these are offers from companies she gave permission to keep in touch with her. She doesn't think of it as spam and the separate bucket is just a convention to her for reviewing offers. I believe she, and many other hotmail users are inadvertently flagging marketing messages they opted-in for as spam, but not appreciating the way hotmail treats these reports. Campaign monitor has a 0.25% tolerance for spam at which point they will terminate your account according to the guidelines so I emailed them to let them know that there is a disturbing trend that of the 15 spam complaints, all but 1 was a hotmail account. My theory is that there is something other than a deliberate spam report decision being made. Fortunately the campaign monitor guys are Australian so it was 1pm their time when I sent my message at 11pm from Chicago last night. Within minutes I had a hand crafted response thanking me for my attention to spam and letting me know that I should be in touch again if it continues to rise. I just emailed Matthew with a note to say that we are considering a double opt-in procedure and a note to say "please add adam@w... to your address book" so hopefully that will cool the waters. I'm also sure that this is just teething trouble for our first mailing and subsequent emails will run more smoothly.

If I could do it all over again I would have used the database to categorize the members by membership duration to see if there is a pattern in unsubscribes or spam reports since it is over a year since people opted in. I'm going to speak to the Campaign monitor guys to see if there is a way to update my list with categories after the fact for this purpose. We have another 5,000 members in our database who opted out who will never receive a message from us and lastly 5,000 members who joined before we added the opt-in box. For this last group, we're going to add a yes no question next time they visit the site to see if they want to opt-in. This should make sure we keep growing the list without irritating people!

May 03
2007

Cheadle Fabrications

I finally got around to building the website for my brother-in-law Graham's business Cheadle Fabrications after a year of other items getting in the way. It's been a fast, fun project and took about 4 hours to get it to the state it is in now.  I had a template for the site since I recently worked with Jeff on another manufacturing site Glo-brite.com based in Chicago.  Unlike Glo-brite, Cheadle Fabrications had no prior website and so I pulled the content and the images from their brochures.  My family all live in England and since I knew there would be lags any other way I just charged ahead to get a version of the site up I would proud to own.  The use of ColdFusion only serves to support the templating system right now but a future enhancement will involve hooking the static content panels up to my home-grown CMS "HAM" used in the Globrite site.

I built the site with the keywords and search engine traffic in mind, adding Google Analytics with funnels to track lead generation - the primary goal of the site.  I'm running Google Adwords campaigns focussed on Europe initially to ensure the clickthroughs come from businesses most likely to contact Graham for work.  Over the coming weeks I'll be reporting back about the process behind the adwords campaign and taking the Google website optimizer for a test drive with her content to see if there are more appealing landing pages to inspire visitors to submit requests through the contact form.  A neat feature of AdWords I discovered yesterday is the smart assignment of candidate ad units.  The tool gives you a simple process to try different versions of the content used in an ad to see which one drives the most clickthrus.  If you elect to use the smart assignment feature it works like natural selection where the most successful (highest clickthru) ad unit is shown more frequently than those with low yield.

Cheadle Fabrications is a steel fabrications business based in the North-west of England specializing in supplying components to the fireplace industry like hotboxes and canopies but they also do custom metal shaping projects like supplying some regional schools with stainless steel urinals built from scratch.

Jan 25
2007

ColdFusion Weekly

Shortly after Apple released the Podcast update for my iPod I chugged through the screens on the Apple website subscribing to all kinds of NPR fun plus some random tidbits I thought I'd listen to.  Less than 3 days later I was behind with podcasts backed out the door unlistened to.  So I did the rational thing.  I deleted them all and vowed never to listen again!

Recently I heard about the competition to win passes to CFUnited for ColdFusion weekly podcast listeners so I subscribed to the feed with the intention of snatching some tickets.  I didn't subscribe to any others, just this one.  That was three weeks ago and I'm still listening on the days when I get to stand on the bus because there are no seats left for me to sit and read.  I'm delighted that I have heard each one, maybe a little delayed but I have listened intently, nodded my head in agreement with things I hear and frowned as I disagree.  This morning I even guffawed as I heard the song to wrap the show - "Woman you've got a jive inheritance tree".  It's a good show, well put together and a good format.  They start with the news before getting into a topic, closing with the competition and then throwing a goofy song in at the end.

The show I heard this morning included a piece on Virtual Machines (VM).  I've used VMWare with great success at the office, the first time was to allow me to view IE6 after I upgraded to IE7.  I also installed Firefox 1.5 on there too so I've got four browser versions to play with.  The second one I created was to run an Ubuntu image with EasyVM running the BlueDragon 7 beta. 
The only issue with VM is the RAM size so if you are playing with CF instances I would order some memory to push you over 2GB.

They skimmed briefly over the "old tools" for getting screenshots of your application working on different browsers and OSs but I think they deserve more attention.  If you haven't got the money for all the OS costs and the time to install these VMs, check out Browsercam. We use it at the office after Jeff found it.  Sure it will run your URL through most PDA, Unix, Mac and more browsers but they also offer remote desktop instances too.  This means that next time a user calls to complain about your site looking funky on their Windows 98 machine, you can dial up a remote desktop window, fire up the browser they were using and see exactly how your application works there.

Great job on the Podcast guys and I'm looking forward to my complimentary CFUnited pass ;-) 

Jul 28
2006

The target blank debate

Jeff just sent a link to a the can of worms at Kevin O'Keefe's blog on the debate whether to open links to other sites from your website in a new window (target="_blank") or let them leave your site when they follow the link.  I've been back and forth on the idea myself for some time.  I don't think there is a one size fits all answer to this question but I think it depends on context. 

If I am offering a link to background information which might help you understand the rest of the article as a reference, I am more likely to use a new window to allow the user to skim the article in the other window before popping back with the extra information.  The purpose of this link is more like a sidebar in that regard.  The rest of the time I provide links to deliberately say "hey, you should check this site out" and if they love me they'll be back :-)

Some really great points I enjoyed:

  • "The best blogs send you away ".  I agree, the value of the blog is to pursuade you that something is worth your time and you return to my blog because you value my opinion (or like to argue with me).
  • "Any true "expert" of the internet would know that there is no room for experts".  Quality.  Black and white statements are for photographers.
Some people missed the boat completely that the author was talking specifically about blogs and not websites.  At our company the discussion rages on with some of our marketing folk insisting that new windows keep people on our site and focussed.  I think a website can be different than a blog since, indeed, your goal is to provide content to stimulate a call to action - register, purchase, contact, learn more.

Jun 29
2006

CFUnited mid-conference roundup

The sun came out in DC yesterday as the conference began and the city is breathing a sigh of relief. ColdFusion can do that :-) I'll try and keep it short but you all know how I can ramble on...

CF Roadmap keynote: I agree with my coworker Kelly that the Adobe influence on CF looks ominous. It's clear that PDF integration for CF jumped the queue at the expense of other key features that were left out. "Scorpio", the next release of ColdFusion, will include some new PDF form based tags to allow users to fill forms in online. That's about it from that angle. Flex 2 was launched officially yesterday and Ben Forta gave a demo of a wizard to build a master-detail web application without writing any code. I could see us thinking about this for our CMS duoCMS for the content administration since it offers some saucy looking UI out of the box.

Sean Corfield talked for an hour on factories in the context of ColdSpring, a framework Duo Consulting (my employer) can and should leverage for all of our CMS cfcs. As it stands, the CMS is built in a way that forces us to keep only one version on each server. ColdSpring would allow us to maintain multiple builds of the code so that a client who was built on duoCMS 1.1.345 would have identical CMS to another client operating on the same build number. This is HUGE for Duo since we can easily identify a fix for one customer and know that it can be fixed for all clients on that build version. It also allows us to plot upgrade paths for clients based on their build number. I know this isn't as exciting as my design buddy Jeff's new addition to the family but it's a close second :-) The other advantage of the framework is that it allows us to hotswap different databases for an individual client so they are still duoCMS but the connectors for getting and setting information in the database are broken out. Fusebox 5 release candidate 1 was also released on Tuesday but I haven't had a chance to look at the details yet.

Note: if you are wondering where I have the time for this in the middle of the day, Kelly is attending the Microsoft Atlas presentation on their attempt at an AJAX library. The part I saw was too intense about Visual Studio so I skipped out.

Next up was Joey Coleman, a thoroughly entertaining speaker describing the concept of having turning yourself into an IPO. Not about starting a business but just managing your career as a brand to maximise your earning potential. Things like getting testimonials from your manager about the work you do and taking stock once a year with an annual report. This can make you more productive and help you realize whether you are stagnating and need more training or need to dig in a little more.

Douglas Ward gave an average presentation on Fundamentals of Usability. The issue was that it was another Jakob Nielsen style "Don't do this, don't do that" and not enough "You should do this". Darn negativity drives me crazy. If anyone has any good recommendations on authors or books describing what should be done please let me know. The only good thing I took away was his analogy of your website as a billboard and the notion that an effective billboard is short, sweet and to the point "Good chicken next exit at Bob's" vs a long winded flowery pile of text which doesn't help the user get to their end point.

An Adobe presenter, Sarge Sargent gave a disappointing talk on gateways with little substance so it looks like I will need to dig in more myself.

John Ashenfelter talked about Agile Programming as a methodology. There was a lot of content and theory but less practical. It would have been better if he had revised his material to focus on the audience: every coder here either builds websites or reports so with that assumption I wanted him to say "a client wants a new website, here is how the process works". I still have pages scribbled on the topic if anyone wants detail. The nugget here was the use of ANT as a tool for web development. Built into the tools most of our developers use it allows you to automate the deployment of applications and the configuration to setup a project. In our environment this would reduce some of the lead time necessary to set our machines up for maintenance of client websites and grab local copies. He also recommended some great development books he believes every developer you hire should read as part of their job requirements.

This morning, slightly less awake I watched Joe Rinehart introduce Model-glue unity as a framework for rapidly developing ColdFusion applications with a ruby on rails for ColdFusion feel. In five minutes he built a rudimentary blog from scratch typing every line of code while we watched in awe. The key component is something called reactor which works on most database platforms through JDBC. It understands the database design and then creates the pages with Model-glue to list, edit, add and delete items.

Lastly, I watched a friend from Atlanta present the benefits of running BlueDragon on .NET - our company sysadmin and I will need to try a demo of this because the benefits are huge including the ability to leverage application pools allowing you to start and stop one part of a website without bringing down the whole site or any other clients on the server. It also means better monitoring abilities and helps us see which client site is bringing the others down.

Food is being served now so I'll wrap up. Great conference, great content and a really good crowd.

More Entries