2

Right now I'm trying to parse a date that's written in a human-readable format into a DateTime String that a SharePoint list will accept. In order to do this I've determined that I need a String in a format similar to ISO that looks like: 2007-08-20T00:00:00Z. It seems that SharePoint only accepts DateTimes that are in UTC with no milliseconds included (for whatever reason, SharePoint gives errors and won't accept the DateTime when you include the milliseconds), so I need to convert my local time into a UTC time before converting it to the ISO string.

Here's the process that the code below is using.

  1. First I use DateJS to parse my human-date into a JavaScript Date. (Works fine, but apparently DateJS has been abandoned, so maybe I should change this to use MomentJS.)
  2. Next I tried to create a new moment in UTC. (This line is very, very wrong, and crashes my program.)
  3. Then I have SPServices convert it into an ISO. SPServices drops the milliseconds off the DateTime so that SharePoint will accept it. (Works fine).

I'm sure there has to be a more elegant/working way to achieve this, instead of stitching together 3 different libraries. I'm just not sure what it is.

var jScriptStartDate = Date.parse("6/29/2014 8:30am"); //JS Date
var jScriptStartDateUTC = moment(jScriptStartDate).utc(); //local date to UTC.
var startDate = $().SPServices.SPConvertDateToISO({ //Sharepoint ISO 8601 format
   dateToConvert: jScriptStartDateUTC,
   dateOffset: "" //Sharepoint dates only accept UTC times, aka no dateOffset.
});
newItem.set_item('EventDate', startDate); //EventDate is internal for StartTime
nsx
  • 697
  • 1
  • 13
  • 41
Ectropy
  • 1,533
  • 4
  • 20
  • 37

2 Answers2

6

You can just use moment.js, and this is all in the documentation.

moment('6/29/2014 8:30am','M/D/YYYY h:mma').toISOString()

This assumes all of the following:

  • The source value is in the user's time zone (that is - the time zone of the machine where the JavaScript code is running)

  • The input will always be in the specified format

It's also worth mentioning that if you put a space before the "am", that most modern browsers can do this natively without any library:

new Date('6/29/2014 8:30 am').toISOString()

If you take that approach, realize that the date parts are ordered according to the users locale, which might be m/d/y, or d/m/y or y/m/d.

Also, you said in the title "... with no milliseconds", but didn't elaborate on that in your question. I'm fairly certain you can pass the milliseconds without issue. There's no good reason to go out of your way to remove them. But if you must, then that would be like this with moment:

moment('6/29/2014 8:30am','M/D/YYYY h:mma').utc().format('YYYY-MM-DD[T]HH:mm:ss[Z]')
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • 1
    I must agree, there certainly seems to be no good reason to remove the milliseconds, but for some bizarre reason SharePoint won't accept any DateTime that isn't stripped of the milliseconds, i.e. in the format `YYYY-MM-DDThh:mm:ssZ`. Also, great answer. I ended up finding an solution that uses only DateJS (but wasn't able to post it, because there is an 8 hour time limit on answering your own question for low-rep users), so I'll post that tomorrow for people who are interested in going that route. – Ectropy Jun 12 '14 at 04:37
  • Watch the casing if you use that with moment. `hh` is 12 hour clock, `HH` is 24 hour. Personally, I recommend moment over DateJS, but if you must use DateJS, please consider the actively maintained fork. [See here for details](http://stackoverflow.com/tags/datejs/info). – Matt Johnson-Pint Jun 12 '14 at 04:54
  • Will do, my current implementation is using the new DateJS fork. I scrapped the old one when I read about it having many bugs that will never be addressed. Also, thanks for the tip about the proper way to write hours. Too bad I can't edit comments and fix what I wrote... – Ectropy Jun 12 '14 at 05:02
  • After 2.13.0, you can simply call: moment('6/29/2014 8:30am','M/D/YYYY h:mma').utc().format(); which will return a YYYY-MM-DDTHH:mm:ssZ string – DarkNeuron Mar 16 '17 at 12:36
  • @DarkNeuron - Good point. Either `.toISOString()` or `.utc().format()` will work. Though, do note that the latter will also switch the moment object overt to UTC mode unless you clone it first. – Matt Johnson-Pint Mar 16 '17 at 16:35
  • `utc().format()` is rfc3339 compatible. Worth noting. – DarkNeuron Mar 16 '17 at 20:34
2

I ended up adjusting this code to use the updated DateJS (https://github.com/abritinthebay/datejs/) and a custom function I made called .toShortISOString().

The process is down to 3 lines:

var jScriptStartDate = Date.parse("6/28/2014 8:00am"); //convert to Javascript Date
var startDate = jScriptStartDate.toShortISOString(); //convert to Sharepoint ISO format (UTC with no milliseconds)
newItem.set_item('EventDate', startDate); //Strangely the internal name for Start Time is EventDate

.toShortISOString()'s main change is the removal of milliseconds, since SharePoint doesn't like milliseconds. It's code looks like this inside of the date.js file:

if ( !$P.toShortISOString ) {
        $P.toShortISOString = function() {
            return this.getUTCFullYear() +
            "-" + p(this.getUTCMonth() + 1) +
            "-" + p(this.getUTCDate()) +
            "T" + p(this.getUTCHours()) +
            ":" + p(this.getUTCMinutes()) +
            ":" + p(this.getUTCSeconds()) +
            //Remove the milliseconds.
            //"." + String( (this.getUTCMilliseconds()/1000).toFixed(3)).slice(2, 5) +
            "Z";
        };
    }

If you're trying to add this to date.js, make sure you have the latest version from the link above, then search the file for toISOString and place the code right below the handler for toISOString.

Ectropy
  • 1,533
  • 4
  • 20
  • 37
  • Glad you liked my updated version of DateJS! :) That's not a bad idea (and looks like you just copied and modified the toISOString method), but in your case it would be as simple as: `var startDate = Date.parse(yourStringDate).toString("yyyy-MM-ddTHH:mm:ss");` Takes it from 3 lines to 2 :) Either works though! – abritinthebay Jun 13 '14 at 17:42
  • Yep, I just copied the toISOString method, and made the one change. The code is very readable (it's really obvious what each line does), which is nice and made it easy to do. Looks like that solution of yours is pretty good too, but wouldn't the string format need to be like `yyyy-MM-ddTHH:mm:ssZ`since a UTC ISO date ends in "Z"? – Ectropy Jun 13 '14 at 20:13
  • Correct! Typo on my part that's true. `.format` would provide you with additional options too - so you could get non-UTC with the non-UTC (local) timezone as well. – abritinthebay Jun 13 '14 at 23:09
  • That sounds like it would be handy if you wanted to convert to UTC for storage then back into local time for your users to see. I'll keep it in mind if I'm writing a system like that in the future. – Ectropy Jun 14 '14 at 14:31