Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix parsing for months/weekdays with weird characters #3078

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/lib/locale/prototype.js
Expand Up @@ -57,7 +57,11 @@ import {
localeWeekdaysParse,
defaultLocaleWeekdays, localeWeekdays,
defaultLocaleWeekdaysMin, localeWeekdaysMin,
defaultLocaleWeekdaysShort, localeWeekdaysShort
defaultLocaleWeekdaysShort, localeWeekdaysShort,

defaultWeekdaysRegex, weekdaysRegex,
defaultWeekdaysShortRegex, weekdaysShortRegex,
defaultWeekdaysMinRegex, weekdaysMinRegex
} from '../units/day-of-week';

proto.weekdays = localeWeekdays;
Expand All @@ -68,6 +72,13 @@ proto.weekdaysShort = localeWeekdaysShort;
proto._weekdaysShort = defaultLocaleWeekdaysShort;
proto.weekdaysParse = localeWeekdaysParse;

proto._weekdaysRegex = defaultWeekdaysRegex;
proto.weekdaysRegex = weekdaysRegex;
proto._weekdaysShortRegex = defaultWeekdaysShortRegex;
proto.weekdaysShortRegex = weekdaysShortRegex;
proto._weekdaysMinRegex = defaultWeekdaysMinRegex;
proto.weekdaysMinRegex = weekdaysMinRegex;

// Hours
import { localeIsPM, defaultLocaleMeridiemParse, localeMeridiem } from '../units/hour';

Expand Down
181 changes: 175 additions & 6 deletions src/lib/units/day-of-week.js
@@ -1,10 +1,12 @@
import { addFormatToken } from '../format/format';
import { addUnitAlias } from './aliases';
import { addRegexToken, match1to2, matchWord } from '../parse/regex';
import { addRegexToken, match1to2, matchWord, regexEscape } from '../parse/regex';
import { addWeekParseToken } from '../parse/token';
import toInt from '../utils/to-int';
import isArray from '../utils/is-array';
import { createLocal } from '../create/local';
import indexOf from '../utils/index-of';
import hasOwnProp from '../utils/has-own-prop';
import { createUTC } from '../create/utc';
import getParsingFlags from '../create/parsing-flags';

// FORMATTING
Expand Down Expand Up @@ -37,9 +39,15 @@ addUnitAlias('isoWeekday', 'E');
addRegexToken('d', match1to2);
addRegexToken('e', match1to2);
addRegexToken('E', match1to2);
addRegexToken('dd', matchWord);
addRegexToken('ddd', matchWord);
addRegexToken('dddd', matchWord);
addRegexToken('dd', function (isStrict, locale) {
return locale.weekdaysMinRegex(isStrict);
});
addRegexToken('ddd', function (isStrict, locale) {
return locale.weekdaysShortRegex(isStrict);
});
addRegexToken('dddd', function (isStrict, locale) {
return locale.weekdaysRegex(isStrict);
});

addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
var weekday = config._locale.weekdaysParse(input, token, config._strict);
Expand Down Expand Up @@ -92,9 +100,77 @@ export function localeWeekdaysMin (m) {
return this._weekdaysMin[m.day()];
}

function handleStrictParse(weekdayName, format, strict) {
var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
if (!this._weekdaysParse) {
this._weekdaysParse = [];
this._shortWeekdaysParse = [];
this._minWeekdaysParse = [];

for (i = 0; i < 7; ++i) {
mom = createUTC([2000, 1]).day(i);
this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
}
}

if (strict) {
if (format === 'dddd') {
ii = indexOf.call(this._weekdaysParse, llc);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return ii !== -1 ? ii : null;
} else if (format === 'ddd') {
ii = indexOf.call(this._shortWeekdaysParse, llc);
return ii !== -1 ? ii : null;
} else {
ii = indexOf.call(this._minWeekdaysParse, llc);
return ii !== -1 ? ii : null;
}
} else {
if (format === 'dddd') {
ii = indexOf.call(this._weekdaysParse, llc);
if (ii !== -1) {
return ii;
}
ii = indexOf.call(this._shortWeekdaysParse, llc);
if (ii !== -1) {
return ii;
}
ii = indexOf.call(this._minWeekdaysParse, llc);
return ii !== -1 ? ii : null;
} else if (format === 'ddd') {
ii = indexOf.call(this._shortWeekdaysParse, llc);
if (ii !== -1) {
return ii;
}
ii = indexOf.call(this._weekdaysParse, llc);
if (ii !== -1) {
return ii;
}
ii = indexOf.call(this._minWeekdaysParse, llc);
return ii !== -1 ? ii : null;
} else {
ii = indexOf.call(this._minWeekdaysParse, llc);
if (ii !== -1) {
return ii;
}
ii = indexOf.call(this._weekdaysParse, llc);
if (ii !== -1) {
return ii;
}
ii = indexOf.call(this._shortWeekdaysParse, llc);
return ii !== -1 ? ii : null;
}
}
}

export function localeWeekdaysParse (weekdayName, format, strict) {
var i, mom, regex;

if (this._weekdaysParseExact) {
return handleStrictParse.call(this, weekdayName, format, strict);
}

if (!this._weekdaysParse) {
this._weekdaysParse = [];
this._minWeekdaysParse = [];
Expand All @@ -105,7 +181,7 @@ export function localeWeekdaysParse (weekdayName, format, strict) {
for (i = 0; i < 7; i++) {
// make the regex if we don't have it already

mom = createLocal([2000, 1]).day(i);
mom = createUTC([2000, 1]).day(i);
if (strict && !this._fullWeekdaysParse[i]) {
this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
Expand Down Expand Up @@ -160,3 +236,96 @@ export function getSetISODayOfWeek (input) {
// as a setter, sunday should belong to the previous week.
return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
}

export var defaultWeekdaysRegex = matchWord;
export function weekdaysRegex (isStrict) {
if (this._weekdaysParseExact) {
if (!hasOwnProp(this, '_weekdaysRegex')) {
computeWeekdaysParse.call(this);
}
if (isStrict) {
return this._weekdaysStrictRegex;
} else {
return this._weekdaysRegex;
}
} else {
return this._weekdaysStrictRegex && isStrict ?
this._weekdaysStrictRegex : this._weekdaysRegex;
}
}

export var defaultWeekdaysShortRegex = matchWord;
export function weekdaysShortRegex (isStrict) {
if (this._weekdaysParseExact) {
if (!hasOwnProp(this, '_weekdaysRegex')) {
computeWeekdaysParse.call(this);
}
if (isStrict) {
return this._weekdaysShortStrictRegex;
} else {
return this._weekdaysShortRegex;
}
} else {
return this._weekdaysShortStrictRegex && isStrict ?
this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
}
}

export var defaultWeekdaysMinRegex = matchWord;
export function weekdaysMinRegex (isStrict) {
if (this._weekdaysParseExact) {
if (!hasOwnProp(this, '_weekdaysRegex')) {
computeWeekdaysParse.call(this);
}
if (isStrict) {
return this._weekdaysMinStrictRegex;
} else {
return this._weekdaysMinRegex;
}
} else {
return this._weekdaysMinStrictRegex && isStrict ?
this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
}
}


function computeWeekdaysParse () {
function cmpLenRev(a, b) {
return b.length - a.length;
}

var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
i, mom, minp, shortp, longp;
for (i = 0; i < 7; i++) {
// make the regex if we don't have it already
mom = createUTC([2000, 1]).day(i);
minp = this.weekdaysMin(mom, '');
shortp = this.weekdaysShort(mom, '');
longp = this.weekdays(mom, '');
minPieces.push(minp);
shortPieces.push(shortp);
longPieces.push(longp);
mixedPieces.push(minp);
mixedPieces.push(shortp);
mixedPieces.push(longp);
}
// Sorting makes sure if one weekday (or abbr) is a prefix of another it
// will match the longer piece.
minPieces.sort(cmpLenRev);
shortPieces.sort(cmpLenRev);
longPieces.sort(cmpLenRev);
mixedPieces.sort(cmpLenRev);
for (i = 0; i < 7; i++) {
shortPieces[i] = regexEscape(shortPieces[i]);
longPieces[i] = regexEscape(longPieces[i]);
mixedPieces[i] = regexEscape(mixedPieces[i]);
}

this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should each piece be escaped ? Note, there is RegExp.escape function in es6

this._weekdaysShortRegex = this._weekdaysRegex;
this._weekdaysMinRegex = this._weekdaysRegex;

this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
}
50 changes: 48 additions & 2 deletions src/lib/units/month.js
Expand Up @@ -8,6 +8,7 @@ import { hooks } from '../utils/hooks';
import { MONTH } from './constants';
import toInt from '../utils/to-int';
import isArray from '../utils/is-array';
import indexOf from '../utils/index-of';
import { createUTC } from '../create/utc';
import getParsingFlags from '../create/parsing-flags';

Expand Down Expand Up @@ -73,9 +74,54 @@ export function localeMonthsShort (m, format) {
this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
}

function handleStrictParse(monthName, format, strict) {
var i, ii, mom, llc = monthName.toLocaleLowerCase();
if (!this._monthsParse) {
// this is not used
this._monthsParse = [];
this._longMonthsParse = [];
this._shortMonthsParse = [];
for (i = 0; i < 12; ++i) {
mom = createUTC([2000, i]);
this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
}
}

if (strict) {
if (format === 'MMM') {
ii = indexOf.call(this._shortMonthsParse, llc);
return ii !== -1 ? ii : null;
} else {
ii = indexOf.call(this._longMonthsParse, llc);
return ii !== -1 ? ii : null;
}
} else {
if (format === 'MMM') {
ii = indexOf.call(this._shortMonthsParse, llc);
if (ii !== -1) {
return ii;
}
ii = indexOf.call(this._longMonthsParse, llc);
return ii !== -1 ? ii : null;
} else {
ii = indexOf.call(this._longMonthsParse, llc);
if (ii !== -1) {
return ii;
}
ii = indexOf.call(this._shortMonthsParse, llc);
return ii !== -1 ? ii : null;
}
}
}

export function localeMonthsParse (monthName, format, strict) {
var i, mom, regex;

if (this._monthsParseExact) {
return handleStrictParse.call(this, monthName, format, strict);
}

if (!this._monthsParse) {
this._monthsParse = [];
this._longMonthsParse = [];
Expand Down Expand Up @@ -207,6 +253,6 @@ function computeMonthsParse () {

this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
this._monthsShortRegex = this._monthsRegex;
this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')$', 'i');
this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')$', 'i');
this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
}
18 changes: 18 additions & 0 deletions src/lib/utils/index-of.js
@@ -0,0 +1,18 @@
var indexOf;

if (Array.prototype.indexOf) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Es6 must provide it, please dont reinvent wheel.

indexOf = Array.prototype.indexOf;
} else {
indexOf = function (o) {
// I know
var i;
for (i = 0; i < this.length; ++i) {
if (this[i] === o) {
return i;
}
}
return -1;
};
}

export { indexOf as default };
1 change: 1 addition & 0 deletions src/locale/ar-ma.js
Expand Up @@ -11,6 +11,7 @@ export default moment.defineLocale('ar-ma', {
weekdays : 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
weekdaysShort : 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
weekdaysParseExact : true,
longDateFormat : {
LT : 'HH:mm',
LTS : 'HH:mm:ss',
Expand Down
1 change: 1 addition & 0 deletions src/locale/ar-sa.js
Expand Up @@ -34,6 +34,7 @@ export default moment.defineLocale('ar-sa', {
weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
weekdaysParseExact : true,
longDateFormat : {
LT : 'HH:mm',
LTS : 'HH:mm:ss',
Expand Down
1 change: 1 addition & 0 deletions src/locale/ar-tn.js
Expand Up @@ -9,6 +9,7 @@ export default moment.defineLocale('ar-tn', {
weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'),
weekdaysParseExact : true,
longDateFormat: {
LT: 'HH:mm',
LTS: 'HH:mm:ss',
Expand Down
1 change: 1 addition & 0 deletions src/locale/ar.js
Expand Up @@ -67,6 +67,7 @@ export default moment.defineLocale('ar', {
weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
weekdaysParseExact : true,
longDateFormat : {
LT : 'HH:mm',
LTS : 'HH:mm:ss',
Expand Down
1 change: 1 addition & 0 deletions src/locale/az.js
Expand Up @@ -31,6 +31,7 @@ export default moment.defineLocale('az', {
weekdays : 'Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə'.split('_'),
weekdaysShort : 'Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən'.split('_'),
weekdaysMin : 'Bz_BE_ÇA_Çə_CA_Cü_Şə'.split('_'),
weekdaysParseExact : true,
longDateFormat : {
LT : 'HH:mm',
LTS : 'HH:mm:ss',
Expand Down
1 change: 1 addition & 0 deletions src/locale/br.js
Expand Up @@ -54,6 +54,7 @@ export default moment.defineLocale('br', {
weekdays : 'Sul_Lun_Meurzh_Merc\'her_Yaou_Gwener_Sadorn'.split('_'),
weekdaysShort : 'Sul_Lun_Meu_Mer_Yao_Gwe_Sad'.split('_'),
weekdaysMin : 'Su_Lu_Me_Mer_Ya_Gw_Sa'.split('_'),
weekdaysParseExact : true,
longDateFormat : {
LT : 'h[e]mm A',
LTS : 'h[e]mm:ss A',
Expand Down
2 changes: 2 additions & 0 deletions src/locale/bs.js
Expand Up @@ -61,9 +61,11 @@ function translate(number, withoutSuffix, key) {
export default moment.defineLocale('bs', {
months : 'januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar'.split('_'),
monthsShort : 'jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.'.split('_'),
monthsParseExact: true,
weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
weekdaysParseExact : true,
longDateFormat : {
LT : 'H:mm',
LTS : 'H:mm:ss',
Expand Down