Javascript Dates, Assumptions, and <ui:inputDate> in Lightning

I've been playing around with Lightning to do some charting recently, and the chart display is driven by two date fields. At first I implemented everything without the UI controls, and then moved on to expanding the functionality once the core was working correctly. In doing so I tripped over a couple of gotchas that any Lightning developer should be aware of.

1. <ui:inputDate> Doesn't Work With Dates

Ok, confusing title, but basically I was dealing with dates so in my initial prototype work I was using JavaScript's Date object, as well as using the Date type for my components' attributes:

<aura:attribute name="rangeStart" type="Date"/>

This all worked well, and then I added the <ui:inputDate> fields, and it all stopped working, and I couldn't work out why the following code wasn't setting the input values correctly:

component.set('v.rangeStart', new Date());

when they were bound to the attributes like so:

<ui:inputDate aura:id="startDate" label="Start" class="field" value="{!v.rangeStart}" displayDatePicker="true"/>

It turns out, when you read the documentation and don't make assumptions that the <ui:inputDate> component works with Strings, and expects you to provide to set values using code like this:

component.set('v.rangeStart', start.getFullYear() + "-" + (start.getMonth() + 1) + "-" + start.getDate());

I do understand that JavaScript date objects have a time component (as well as a timezone) and that complicates things, but having every developer write code along these lines seems a little crazy. Also, converting to use strings lead me to my next issue.

2. Beware of the Date Parser

Since I was only doing very basic date operations I decided against pulling in a library just as Moment.js, because frankly I think the world has gone library mad. The thing with libraries though is that they often handle edge cases you may not be aware of.

I encountered a bug just now where one of my date attributes that was being modified by the <ui:inputDate> control was resulting in a JavaScript date object where the time component was non-zero, and actually happened to correspond with the current time difference between my timezone and UTC:

var someDate = new Date(component.get("v.rangeStart"));

someDate as parsed from my non-edited field:

> Wed Feb 01 2017 00:00:00 GMT+1100 (AUS Eastern Summer Time)

someDate as parsed when clicking on the and selecting the same date

> Wed Feb 01 2017 11:00:00 GMT+1100 (AUS Eastern Summer Time)

So what gives? Obviously the difference is caused by the value stored in the date attribute, so that was what I checked out first, and led me almost immediately to the answer. The code snippet above in point 1 that sets the attribute's value doesn't include leading zeros. The strings that are created by the <ui:inputDate> component itself do include leading zeros. In this browser at least (and I suspect others given that there's only really a few JS engines knocking about) the use of leading zeroes or not changes how the string is parsed:

> new Date("2017-02-1");
< Wed Feb 01 2017 00:00:00 GMT+1100 (AUS Eastern Summer Time)  
> new Date("2017-02-01");
< Wed Feb 01 2017 11:00:00 GMT+1100 (AUS Eastern Summer Time)  

This doesn't surprise me as when it comes to programming and dates you should never, never, never make assumptions of any kind, but sometimes it's hard not to and frankly I'm just thankful that this one didn't take too long to work out.

comments powered by Disqus