Convert JavaScript DateTime to UTC with no milliseconds - datetime

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.
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.)
Next I tried to create a new
moment in UTC. (This line is very, very wrong, and crashes my
program.)
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

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]')

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.

Related

MomentJS - convert YYYYMMDD and HH:MM to YYYY-MM-DDThh:mm:ss

I get two separate time and date values from my API.
date: 20190404
time: 09:30
I want to combine the two in one acceptable format, such as YYYY-MM-DDThh:mm:ss.
I have tried the following:
moment(data[i].date + 'T' + data[i].time).valueOf()
but I get the following error in the console:
Deprecation warning: value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.
and the value in my array shows as 'NaN'
Thanks!
Concatenate the date and time without space and add the format as the second parameter of moment()
var moment = require("moment")
var data = {date: '20190404',
time: '09:30'}
var joined = `${data.date}${data.time}`
console.log(moment(joined, 'YYYYMMDDh:mm:ss').format())
// "2019-04-04T09:30:00+01:00"

Moment.js doesn't support Microsoft/ISO format?

I'm working on a project where I'm given the Microsoft date/time format, which seems to be exactly like a standard ISO formatting.
When I try to format a date with Moment.js, it doesn't come out right. For example, the format I'm provided with has 'yy' for the 2-digit year and 'd' for a 1-digit day-of-month.
When I look at the Moment.js format documentation I realize the it doesn't even support it? That's a bit odd? Why would it not support a standard?
Or am I doing something wrong? Am I missing something?
I'd really hate to try to write an ISO to Moment.js format converter.
Has anyone had the same problems? If so, how have you resolved this?
Update 2017.10.16 17:32:
After getting a good question from Matt Johnson down in the comment, I read my post again and realized I've been working for so long in this "embedded" web project that I probably wasn't quite clear as to what is meant by "windows giving me a date format". So I wrote the following in response to his question:
#MattJohnson, what I mean is that the web project I'm working on for a client is an IE embedded (OLE) inside a Windows application (compiled binary, not web). The JavaScript portion of the web application "talks" to the desktop application in order to receive/send data. One of the data I receive is a "dateFormat" and "timeFormat" property. The values I receive, I'm told come directly from the Windows machine (based on user configuration of that OS). It happens that years/days are all lowercase, causing Moment.js to not being able to format dates properly. Thus the conversion I now have.
Examples:
Calling
moment().format();
Will produce
"2017-10-13T13:24:47-04:00"
Now, if I want to format it according to the Moment.js documentation, I'd do this:
moment().format('MM/DD/YYYY');
To get this:
"10/13/2017"
The problem is that Windows passes along this format:
"dd/MM/yyyy"
So when I call Moment with it, like:
moment().format('dd/MM/yyyy');
Giving me this:
"Ve/30/yyyy"
While I was expecting this:
13/10/2017
When I look at many other date formatting libraries, I see that they all support the 'yyyy', 'dd' and 'MM' structure. But not Moment.js.
Update 2017.10.13 16:41:
I did a comparison of Microsoft's date/time format to that of Moment.js and saw the differences.
* ---------------------------------------------------------------------------------------------
* Unit Microsoft Examples Moment.js Differnces?
* ---------------------------------------------------------------------------------------------
* day d, dd 1, 01 D, DD Yes, case
* day of week ddd, dddd Fri, Friday ddd, dddd None
* month M, MM, MMM, MMMM 8, 08, Oct., October M, MM, MMM, MMMM None
* year yy, yyyy 17, 2017 YY, YYYY Yes, case
*
* hour h, hh, H, HH 3, 03, 15, 15 h, hh, H, HH None
* minutes m, mm 9, 09 m, mm None
* seconds s, ss 5, 05 s, ss None
*/
Using that information, I quickly wrote a format conversion function:
function windowsFormatToMomentJSFormat(windowsFormat) {
var format = windowsFormat;
console.log("Converting date format...");
if (!windowsFormat) return format;
console.log(" > From : '" + windowsFormat + "'");
format = format.replace(/y/g, 'Y'); // Fix case for years
format = format.replace(/d{4}/g, '#'); // Protect 4-digit DOW sequence
format = format.replace(/d{3}/g, '&'); // Protect 3-digit DOW sequence
format = format.replace(/d/g, 'D'); // Fix case for days
format = format.replace(/#/g, 'dddd'); // Restore our sequence
format = format.replace(/&/g, 'ddd'); // Restore our sequence
console.log(" > To : '" + format + "'");
console.log(" > Applied : '" + moment().format(format) + "'");
return format;
}
It seems to work well, although I wish I was much better at advanced REGEX in order optimize the function and remove the protect/restore code.
So now, my Windows format strings seems to be processed correctly by Moment.js' format() function.
Yes, you will need a conversion function, because date/time formatting tokens are different across various libraries and platforms. There isn't one already developed, that I am aware of.
This is the list of formatting tokens supported in Moment
This is the list of formatting tokens supported in .NET, which is roughly the same as the ones used in the Windows date/time region settings.
Here is a moment plugin that does almost what you want, but it uses Java's token set, not Windows. You could base your implementation on that.
Note that your current function is missing several tokens. In particular the am/pm separator needs translation, and you should think about literals and escape sequences as well.

Format hours, minutes and seconds with moment.js

I get this value from my backend service: 171054. It represents hh:mm:ss. But when I use the formatting options from the docs it gives me back 00:00:00.
Things I've tried:
moment('171054').format('hh-mm-ss')
moment('171054').format('HH-mm-ss')
moment('171054').format('HH-MM-SS')
You are confusing format option with parsing option. Since your input string is not in ISO 8601 format, you have to specify format when parsing.
Here a working example for your use case:
var mom = moment('171054', 'HHmmss');
console.log(mom.format());
console.log(mom.format('HH:mm:ss'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.1/moment.min.js"></script>
I am not sure if momentjs can read that as date since there is no identifier. I would suggest changing the value for example you have 171054, get each 2 digits since you sure that this is represent as hh:mm:ss then add identifier between then like ":" or "-" then try us momentjs formatting again.

moment.js and deprecated warning. timestamp to moment date object

I've read thru various posts on here in regards to similiar issues but none have solved my problem.
I manipulate the moment.js date object, and then store it as timestamp.
BUT, when I try to read in that timestamp again, I get that deprecated warning.
""Deprecation warning: moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info."
I've tried toDate(), format(), moment(myTimeStamp, 'ddd, DD MMM YYYY HH:mm:ss ZZ'); --> all generate the warning...
So, for example, my timestamp will look like this:
const timestamp = '1458586740000'
when I read that back and try to parse out the month/day/year, then the hour/min am/pm, etc... I need to get that timestamp into a moment.js object. Nothing is working for me. Any ideas.
How can I get this timestamp: '1458586740000', into a moment.js object so I can extract date date from it as I need?
EDIT: this is how I am storing the timestamp. So I would need to retrieve it from this.
let timeStamp = Moment(state[_Date])
.add({ hour: state[AMPM] === 'PM'
? +state[Hour] + 12
: state[Hour] ,
minute: state[Min] }).format('x')
The X token indicates a unix timestamp in seconds, and the x token indicates a unix millisecond timestamp (offset).
You appear to have a millisecond timestamp, so you would make a moment out of it by doing the following:
var a = moment('1458586740000', 'x')
It works without ' as well:
var a = moment(1458586740000, 'x')
You can also not specify the x and it should work:
moment(1458586740000)
Because you have a unix offset (milliseconds), not a unix timestamp (seconds), moment.unix is not what you want.
Then you can do the following:
a.format()
"2016-03-21T13:59:00-05:00"
Or you can use any of the other formatting tokens listed here to output whatever result you would like: http://momentjs.com/docs/#/displaying/format/
Based on the code you presented, I think you may be having problems because your timestamp is stored as a string (in ''). Parsing as a string causes an invalid date error, because it attempts to match ISO 8601 format and fails. Specifying that 'x' token will cause it to assume unix offset and work correctly.

Applescript: Convert date into something useful, then perform calculation

I'm trying to create an applescript script that will take a date in the form:
02/20/99
Then, subtract 5 days from the date, and return a date like this:
02/15/99
Here's the basic applescript I have, but, obviously, I'm missing the logic around converting the date into something that I can manipulate (and returning it to something readable by humans).
set itemPath to quoted form of POSIX path of theFile
set dateString to do shell script "awk 'NR == 10 {print $3}' " & itemPath & " -"
set myDueDate to dateString - (5 * days)
set theTask to "Pay AMEX bill"
tell application "OmniFocus"
tell front document
set theContext to first flattened context where its name = "OFFICE"
set theProject to first flattened context where its name = "Bookkeeping - PMS"
tell theProject to make new task with properties {name:theTask, context:theContext, due date:myDueDate}
end tell
end tell
Thanks in advance!
I think these lines should be sufficient for what you need:
set dateString to "02/20/99"
set thisDate to date dateString
set fiveDaysEarlier to thisDate - 5 * days
log date string of fiveDaysEarlier
log short date string of fiveDaysEarlier
This page has some more examples of the coercions supported when converting strings to objects of date class:
AppleScript Class Reference: date
Also, it probably goes without saying, but the string "02/20/99" is not Y2k compliant, so guesses will have to be made somewhere as to which century this date lies in.
If you get error "FileMaker Pro got an error: Object not found." number -1728, add my before date. e.g,
set thisDate to my date dateString.
When working inside a tell, I think it needs to access methods outside the tell's scope.

Resources