2017-04-18 3 views
1

J'ai une API qui fournit la date dans le format suivant:Comment forcer constructeur Date d'accepter le format sur IE

aaaa-MM-jj'T'HH: mm: ssZ, ce qui est quelque chose comme, par exemple : 2017-04-18T11: 18: 05-0300. Chrome peut créer une date à partir d'une telle chaîne, mais IE ne peut pas. Existe-t-il un moyen de forcer IE à accepter ce format, quel est le moyen le plus simple de résoudre ce problème?

J'ai essayé quelque chose comme l'extrait ci-dessous, mais il ne fonctionne pas

(function() { 

var originalDateFn = Date; 

var month_names_short = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 

Date = function(date) { 
    var splitted = splitIfOnApiFormat(date); 
    if(splitted !== null) { 
    return new Date(month_names_short[splitted[2]] + ' ' + splitted[3] + ' ' + splitted[1] + ' ' + splitted[4] +' GMT'+ splitted[5]); 
    } 
    return originalDateFn(date); 
}; 

function splitIfOnApiFormat(date) { 
    return typeof date === 'string' && date.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}\:\d{2}\:\d{2})([-+]\d{4})$/); 
} 



})(); 
+0

Lorsque je travaille avec des dates dans JS, je suggère d'utiliser moment.js. http://momentjs.com/ – gforce301

+0

Copie possible de [Pourquoi Date.parse donne des résultats incorrects?] (Http://stackoverflow.com/questions/2587345/why-does-date-parse-give-incorrect-results – CBroe

+0

En fait, j'utilise momentjs mais le composant d'entrée de date utilise lui-même Date, donc dans mon cas, le faire fonctionner sur IE serait une solution de rechange nécessaire –

Répondre

1

Le problème dans ce cas est le : manquant entre les heures et les minutes dans la partie de décalage à la fin. À cet égard, IE est dans son droit de signaler cela comme une date non valide, car il n'est pas conforme à la definition of date in the spec, qui est YYYY-MM-DDTHH:mm:ss.sssZ ou YYYY-MM-DDTHH:mm:ss.sss±hh:mm (avec par deux points).

Vous pouvez résoudre ce problème avec:

const date = "2017-04-18T11:18:05-0300"; 
 

 
function fixDate(date) { 
 
    return date.replace(/(\d\d)(\d\d)$/, 
 
    function(_, hh, mm) { return hh + ':' + mm; }); 
 
} 
 

 
console.log(new Date(fixDate(date)));

+0

Merci beaucoup mon pote, beaucoup plus simple et plus correct que ma réponse ci-dessous, en fait je vais changer l'API pour fournir des dates dans ce format. Parfait comme vous avez également fait référence à la spécification que je ne connaissais pas –

-1

OK, il a obtenu Pour toute autre personne qui peut avoir besoin, le code suivant fixé il:

(function() { 

var originalDateFn = Date.prototype.constructor; 

var month_names_short = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 

Date = function(date) { 
    var splitted = splitIfOnApiFormat(date); 
    if(splitted !== null) { 
    return new originalDateFn(month_names_short[(Number(splitted[2])) -1] + ' ' + splitted[3] + ' ' + splitted[1] + ' ' + splitted[4] +' GMT'+ splitted[5]); 
    } 
    return new originalDateFn(date); 
}; 

function splitIfOnApiFormat(date) { 
    return typeof date === 'string' ? date.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}\:\d{2}\:\d{2})([-+]\d{4})$/) : null; 
} 



})(); 
+0

Non !! Une fois que vous avez analysé la chaîne, donnez les parties ** directement ** au constructeur, ne faites pas une autre chaîne qui doit ensuite être analysée. Voir [* Pourquoi Date.parse donne des résultats incorrects? *] (Http://stackoverflow.com/questions/2587345/why-does-date-parse-give-incorrect-results/20463521?s=11|0.4677#20463521 – RobG

+0

Votre expression régulière échouera s'il y a des fractions de secondes. –

0

La règle d'or est de jamais chaînes parse avec l'analyseur intégré (par exemple en utilisant soit le constructeur Date ou Date.parse). Vous avez déjà divisé la chaîne en plusieurs parties, il suffit donc de les transmettre au constructeur Date et de les ajuster pour le fuseau horaire.

Ce qui suit va analyser une chaîne de format étendu ISO 8601 comme spécifié dans ECMA-262, espérons que les commentaires sont suffisants.

/* Parse string in ISO 8601 extended format: YYYY-MM-DDTHH:mm:ss.sssZ. 
 
** Date only strings are treated as local (per ISO 8601) 
 
** 
 
** @param {string} s - string to parse. Can be just a date, date and time, 
 
**      or date, time and timezone. 
 
**      Separator can be T or " " (space) 
 
**      Date string must be at least year and month: YYYY-MM 
 
**      All time parts are optional, if time provided then 
 
**      date must have year, month and day. 
 
**      All time parts are optional. 
 
**      Timezone, if present, must be Z or z or +/-HH:mm or +/-HHmm 
 
** 
 
** @returns {Date} - if s is a invalid date, contains invalid values, 
 
**      or is an invalid format, returns an invalid Date 
 
*/ 
 
function parseISO(s) { 
 

 
    // Create base Date object 
 
    var date = new Date(); 
 
    date.setHours(12, 0, 0, 0); 
 
    var invalidDate = new Date(NaN); 
 

 
    // Set some defaults 
 
    var sign = -1, 
 
    tzMins = 0; 
 
    var tzHr, tzMin; 
 

 
    // Trim leading and trailing whitespace 
 
    s = s.replace(/^\s*|\s*$/g, '').toUpperCase(); 
 

 
    // Get parts of string and split into numbers 
 
    var d = (s.match(/^\d+(-\d+){0,2}/) || [''])[0].split(/\D/); 
 
    var t = (s.match(/[\sT]\d+(:\d+){0,2}(\.\d+)?/) || [''])[0].split(/\D/); 
 
    var tz = (s.match(/Z|[+\-]\d\d:?\d\d$/) || [''])[0]; 
 

 
    // Resolve timezone to minutes, may be Z, +hh:mm or +hhmm 
 
    // substr is old school but more compatible than slice 
 
    // Don't need to split into parts but makes validation easier 
 
    if (tz) { 
 
    sign = /^-/.test(tz) ? 1 : -1; 
 
    tzHr = tz == 'Z' ? 0 : tz.substr(1, 2); 
 
    tzMin = tz == 'Z' ? 0 : tz.substr(tz.length - 2, 2) * 1; 
 
    tzMins = sign * (tzHr * 60 + tzMin); 
 
    } 
 

 
    // Validation 
 
    function isLeap(year) { 
 
    return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); 
 
    } 
 

 
    // Check number of date parts and month is valid 
 
    if (d.length > 3 || d[1] < 1 || d[1] > 12) return invalidDate; 
 

 
    // Test day is valid 
 
    var monthDays = [, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; 
 
    var monthMax = isLeap(d[0]) && d[1] == 2 ? 29 : monthDays[+d[1]]; 
 
    if (d[2] < 1 || d[2] > monthMax) return invalidDate; 
 

 
    // Test time parts 
 
    if (t.length > 5 || t[1] > 23 || t[2] > 59 || t[3] > 59 || t[4] > 999) return invalidDate; 
 

 
    // Test tz within bounds 
 
    if (tzHr > 12 || tzMin > 59) return invalidDate; 
 

 
    // If there's a timezone, use UTC methods, otherwise local 
 
    var method = tz ? 'UTC' : ''; 
 

 
    // Set date values 
 
    date['set' + method + 'FullYear'](d[0], (d[1] ? d[1] - 1 : 0), d[2] || 1); 
 
    // Set time values - first memeber is '' from separator \s or T 
 
    date['set' + method + 'Hours'](t[1] || 0, (+t[2] || 0) + tzMins, t[3] || 0, t[4] || 0); 
 

 
    return date; 
 
} 
 

 
// Some tests 
 
['2017-04-18T11:18:05-0300', // No colon in timezone 
 
    '2017-04-18 11:18:05-0300', // Space separator instead of T 
 
    '2016-04-12T04:31+05:30', // Colon in timezone 
 
    '2016-02-29T04:31+05:30', // Colon, leap year 
 
    '2016-04-12T04:31:56.004Z', // GMT 
 
    '2000-02-29T04:31+05:30', // Colon, leap year 
 
    '1900-02-29T04:31+05:30', // Colon, not leap year (invalid date) 
 
    '2016-04-12T04:31:56.004', // Local 
 
    '2016-04-12',    // Date only (local) 
 
    '2016-04'     // Minimal date (local) 
 
].forEach(function(d) { 
 
    console.log(d + ': ' + parseISO(d).toString()); 
 
});

Vous pouvez également utiliser une bibliothèque, il y a beaucoup de bons à choisir.

+0

L'exception est si vous êtes sûr que l'entrée est dans «YYYY-MM-DDThh: mm: ss.sssZ» ou «YYYY-MM-DDThh: mm: ss .sss ± hh: mm' forme, vous pouvez utiliser en toute sécurité 'Date.parse' ou' new Date'. –

+0

@ torazaburo-je ne crois toujours pas. Il y a beaucoup de bizarreries avec des parseurs intégrés, tellement mieux de ne pas les utiliser du tout à mon humble avis, bien sûr. ;-) – RobG