I have a datetime from Apple's receipt validation server. I need to compare it to today's date. I'm trying to use moment.js but I am fine with native Date as well.
The date is formatted like this, in what Apple's docs claim, incorrectly, is RFC 3339 format:
2017-11-28 23:37:52 Etc/GMT
Since this isn't a valid RFC 3339 or ISO 8601 datetime, it is failing to parse using moment.js or Date.parse(). How can I parse it?
Note that I don't want to simply strip the Etc/ out because its important for determining the correct timezone according to https://opensource.apple.com/source/system_cmds/system_cmds-230/zic.tproj/datfiles/etcetera:
We use POSIX-style signs in the Zone names and the output abbreviations, even though this is the opposite of what many people expect. POSIX has positive signs west of Greenwich, but many people expect positive signs east of Greenwich. For example, TZ='Etc/GMT+4' uses the abbreviation "GMT+4" and corresponds to 4 hours behind UTC (i.e. west of Greenwich) even though many people would expect it to mean 4 hours ahead of UTC (i.e. east of Greenwich).
You can adopt one of two strategies:
The first way is more robust.
The reference doesn't say how timezones like +0530 are represented in the Etc/ format, so the following doesn't deal with them:
Also, the following functions don't validate the format, they assume the supplied string is suitable.
// Parse strings in format 2017-11-28 23:37:52 Etc/GMT
function parsePOZIX(s) {
var b = s.split(' ');
// These are the date and time parts
var c = b[0].split(/\D/).concat(b[1].split(/\D/));
// Create a new Date using UTC
var d = new Date(Date.UTC(c[0],c[1]-1,c[2],c[3],c[4],c[5]));
// Now adjust for the timezone
var tz = b[2].split('/')[1];
var sign = /^\+/.test(tz) ? 1 : -1;
var hr = tz.replace(/\D/g, '') || '0';
d.setUTCHours(d.getUTCHours() + sign*hr);
return d;
}
['2017-11-28 23:37:52 Etc/GMT',
'2017-11-28 23:37:52 Etc/+8',
'2017-11-28 23:37:52 Etc/-10'].forEach(function(s){
console.log(s + '\n' + parsePOZIX(s).toISOString());
});
And the second (less reliable way) which parses and reformats the string, then uses the built-in parser:
// Reformat strings like 2017-11-28 23:37:52 Etc/GMT
// to ISO 8601 compliance, then use built-in parser
function parsePOSIX2(s) {
var b = s.split(' ');
var tz = b[2].split('/')[1];
var sign = /^\+/.test(tz)? '-' : '+';
var hr = tz.replace(/\D/g,'') || '0';
hr = ('0' + hr).slice(-2) + ':00'; // Must include colon for Safari
return new Date(b[0] + 'T' + b[1] + sign + hr);
}
['2017-11-28 23:37:52 Etc/GMT',
'2017-11-28 23:37:52 Etc/-4'].forEach(function(s) {
console.log(s + '\n' + parsePOSIX2(s).toISOString());
});
Note that Safari will not parse a timezone like "+0000" (resulting in an invalid date), it must include a colon: "+00:00".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With