Skip to content

Commit 4ca050a

Browse files
committed
2 parents 2ec7595 + 9db5ea0 commit 4ca050a

File tree

4 files changed

+178
-68
lines changed

4 files changed

+178
-68
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ before_install:
77
install:
88
- npm install
99
- bower install
10+
sudo: false

src/date/expand-pattern.js

Lines changed: 104 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ define([
2727
*/
2828

2929
return function( options, cldr ) {
30-
var dateSkeleton, result, skeleton, timeSkeleton, type;
30+
var dateSkeleton, result, skeleton, timeSkeleton, type, dateTimeSkeleton;
3131

3232
function combineDateTime( type, datePattern, timePattern ) {
3333
return formatMessage(
@@ -56,9 +56,13 @@ return function( options, cldr ) {
5656
});
5757
}
5858

59-
ratedFormats.sort( function( formatA, formatB ) {
60-
return formatA.rate - formatB.rate;
61-
});
59+
ratedFormats = ratedFormats
60+
.filter( function( format ) {
61+
return format.rate > -1;
62+
} )
63+
.sort( function( formatA, formatB ) {
64+
return formatA.rate - formatB.rate;
65+
});
6266

6367
if ( ratedFormats.length ) {
6468
pattern = augmentFormat( skeleton, ratedFormats[0].pattern );
@@ -68,64 +72,93 @@ return function( options, cldr ) {
6872
return pattern;
6973
}
7074

71-
function compareFormats( formatA, formatB ) {
72-
var distance, maxLength, minLength, index;
75+
function repeatStr( str, count ) {
76+
var i, result = "";
77+
for ( i = 0; i < count; i++ ) {
78+
result = result + str;
79+
}
80+
return result;
81+
}
7382

74-
maxLength = Math.max( formatA.length, formatB.length );
75-
minLength = Math.min( formatA.length, formatB.length );
76-
distance = maxLength / minLength;
83+
function normalizePatternType( char ) {
84+
switch ( char ) {
85+
case "e":
86+
case "E":
87+
case "c":
88+
return "e";
7789

78-
formatA = formatA.match( datePatternRe );
79-
formatB = formatB.match( datePatternRe );
80-
maxLength = Math.max( formatA.length, formatB.length );
81-
minLength = Math.min( formatA.length, formatB.length );
90+
case "M":
91+
case "L":
92+
return "L";
8293

83-
for ( index = 0; index < minLength; index++ ) {
84-
if ( formatA[index].charAt( 0 ) === formatB[index].charAt( 0 ) ) {
85-
if ( formatA[index].length === formatB[index].length ) {
86-
distance *= 0.25;
87-
} else {
88-
distance *= 0.75;
89-
}
90-
} else {
91-
distance *= 1.25;
92-
}
94+
default:
95+
return char;
9396
}
97+
}
9498

95-
distance *= 1.25 * ( maxLength - minLength + 1 );
99+
function compareFormats( formatA, formatB ) {
100+
var distance,
101+
typeA,
102+
typeB,
103+
matchFound,
104+
i,
105+
j;
106+
107+
if ( formatA === formatB ) {
108+
return 0;
109+
}
96110

111+
formatA = formatA.match( datePatternRe );
112+
formatB = formatB.match( datePatternRe );
97113
if ( formatA.length === formatB.length ) {
98-
distance *= 0.5;
114+
distance = 1;
115+
for ( i = 0; i < formatA.length; i++ ) {
116+
typeA = normalizePatternType( formatA[i].charAt( 0 ) );
117+
typeB = null;
118+
matchFound = false;
119+
for ( j = 0; j < formatB.length; j++ ) {
120+
typeB = normalizePatternType( formatB[j].charAt( 0 ) );
121+
if ( typeA === typeB ) {
122+
break;
123+
} else {
124+
typeB = null;
125+
}
126+
}
127+
if ( null === typeB ) {
128+
return -1;
129+
}
130+
distance = distance + Math.abs( formatA[i].length - formatB[j].length );
131+
if ( formatA[i].charAt( 0 ) !== formatB[j].charAt( 0 ) ) {
132+
distance = distance + 1;
133+
}
134+
}
135+
return distance;
99136
}
100-
101-
return distance;
137+
return -1;
102138
}
103139

104140
function augmentFormat( requestedSkeleton, bestMatchFormat ) {
105-
var originalBestMatchFormat, index, type, tempIndex;
141+
var i, j, matchedType, matchedLength, requestedType, requestedLength;
106142

107-
originalBestMatchFormat = bestMatchFormat;
108143
requestedSkeleton = requestedSkeleton.match( datePatternRe );
109144
bestMatchFormat = bestMatchFormat.match( datePatternRe );
110145

111-
for ( index in bestMatchFormat ) {
112-
type = bestMatchFormat[index].charAt( 0 );
113-
114-
for ( tempIndex in requestedSkeleton ) {
115-
if ( type === requestedSkeleton[tempIndex].charAt( 0 ) ) {
116-
bestMatchFormat[index] = requestedSkeleton[tempIndex];
117-
break;
146+
for ( i = 0; i < bestMatchFormat.length; i++ ) {
147+
matchedType = bestMatchFormat[i].charAt( 0 );
148+
matchedLength = bestMatchFormat[i].length;
149+
for ( j = 0; j < requestedSkeleton.length; j++ ) {
150+
requestedType = requestedSkeleton[j].charAt( 0 );
151+
requestedLength = requestedSkeleton[j].length;
152+
if (
153+
normalizePatternType( matchedType ) === normalizePatternType( requestedType ) &&
154+
matchedLength < requestedLength
155+
) {
156+
bestMatchFormat[i] = repeatStr( matchedType, requestedLength );
118157
}
119158
}
120159
}
121160

122-
bestMatchFormat = bestMatchFormat.join( "" );
123-
124-
if ( bestMatchFormat === originalBestMatchFormat ) {
125-
bestMatchFormat = requestedSkeleton.join( "" );
126-
}
127-
128-
return bestMatchFormat;
161+
return bestMatchFormat.join( "" );
129162
}
130163

131164
switch ( true ) {
@@ -138,28 +171,37 @@ return function( options, cldr ) {
138171
if ( !result ) {
139172
timeSkeleton = skeleton.split( /[^hHKkmsSAzZOvVXx]/ ).slice( -1 )[ 0 ];
140173
dateSkeleton = skeleton.split( /[^GyYuUrQqMLlwWdDFgEec]/ )[ 0 ];
141-
if ( /(MMMM|LLLL).*[Ec]/.test( dateSkeleton ) ) {
142-
type = "full";
143-
} else if ( /MMMM/g.test( dateSkeleton ) ) {
144-
type = "long";
145-
} else if ( /MMM/g.test( dateSkeleton ) || /LLL/g.test( dateSkeleton ) ) {
146-
type = "medium";
147-
} else {
148-
type = "short";
149-
}
150-
dateSkeleton = getBestMatchPattern(
174+
dateTimeSkeleton = getBestMatchPattern(
151175
"dates/calendars/gregorian/dateTimeFormats/availableFormats",
152-
dateSkeleton
176+
skeleton
153177
);
154-
timeSkeleton = getBestMatchPattern(
155-
"dates/calendars/gregorian/dateTimeFormats/availableFormats",
156-
timeSkeleton
157-
);
158-
159-
if ( dateSkeleton && timeSkeleton ) {
160-
result = combineDateTime( type, dateSkeleton, timeSkeleton );
178+
if ( dateTimeSkeleton ) {
179+
result = dateTimeSkeleton;
161180
} else {
162-
result = dateSkeleton || timeSkeleton;
181+
dateSkeleton = getBestMatchPattern(
182+
"dates/calendars/gregorian/dateTimeFormats/availableFormats",
183+
dateSkeleton
184+
);
185+
timeSkeleton = getBestMatchPattern(
186+
"dates/calendars/gregorian/dateTimeFormats/availableFormats",
187+
timeSkeleton
188+
);
189+
190+
if ( /(MMMM|LLLL).*[Ec]/.test( dateSkeleton ) ) {
191+
type = "full";
192+
} else if ( /MMMM/g.test( dateSkeleton ) ) {
193+
type = "long";
194+
} else if ( /MMM/g.test( dateSkeleton ) || /LLL/g.test( dateSkeleton ) ) {
195+
type = "medium";
196+
} else {
197+
type = "short";
198+
}
199+
200+
if ( dateSkeleton && timeSkeleton ) {
201+
result = combineDateTime( type, dateSkeleton, timeSkeleton );
202+
} else {
203+
result = dateSkeleton || timeSkeleton;
204+
}
163205
}
164206
}
165207
break;

test/functional/date/date-formatter.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ QUnit.test( "should return a formatter", function( assert ) {
6060
assert.equal( Globalize.dateFormatter({ skeleton: "yQQQhm" })( date ), "Q3 2010, 5:35 PM" );
6161
});
6262

63+
QUnit.test( "should augment a skeleton", function( assert ) {
64+
extraSetup();
65+
66+
assert.equal( Globalize.dateFormatter({ skeleton: "yMMMMd" })( date ), "September 15, 2010" );
67+
assert.equal( Globalize.dateFormatter({ skeleton: "MMMMd" })( date ), "September 15" );
68+
assert.equal( Globalize.dateFormatter({ skeleton: "MMMM" })( date ), "September" );
69+
assert.equal( Globalize.dateFormatter({ skeleton: "EEEE" })( date ), "Wednesday" );
70+
});
71+
6372
QUnit.test( "should allow for runtime compilation", function( assert ) {
6473
extraSetup();
6574

test/unit/date/expand-pattern.js

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,83 @@ define([
33
"src/date/expand-pattern",
44
"json!cldr-data/main/de/ca-gregorian.json",
55
"json!cldr-data/main/en/ca-gregorian.json",
6+
"json!cldr-data/main/ru/ca-gregorian.json",
67
"json!cldr-data/supplemental/likelySubtags.json",
78

89
"cldr/event",
910
"cldr/supplemental"
10-
], function( Cldr, expandPattern, deCaGregorian, enCaGregorian, likelySubtags ) {
11+
], function( Cldr, expandPattern, deCaGregorian, enCaGregorian, ruCaGregorian, likelySubtags ) {
1112

12-
var de, en;
13+
var de, en, ru;
1314

14-
Cldr.load( deCaGregorian, enCaGregorian, likelySubtags );
15+
Cldr.load( deCaGregorian, enCaGregorian, ruCaGregorian, likelySubtags );
1516

1617
de = new Cldr( "de" );
1718
en = new Cldr( "en" );
19+
ru = new Cldr( "ru" );
20+
21+
/**
22+
* Test actual patterns here
23+
* @see https://ssl.icu-project.org/icu4jweb/flexTest.jsp
24+
*/
1825

1926
QUnit.module( "Date Expand Pattern" );
2027

28+
2129
QUnit.test( "should expand {skeleton: \"<skeleton>\"}", function( assert ) {
22-
assert.equal( expandPattern( { skeleton: "GyMMMEd" }, en ), "E, MMM d, y G" );
23-
assert.equal( expandPattern( { skeleton: "GyMMMEdhms" }, en ), "E, MMM d, y G, h:mm:ss a" );
24-
assert.equal( expandPattern( { skeleton: "MMMMEdhm" }, de ), "E, d. MMMM 'um' h:mm a" );
30+
var cldrs = {
31+
en: en,
32+
de: de,
33+
ru: ru
34+
};
35+
var cases = {
36+
en: {
37+
"GyMMMEd": "E, MMM d, y G",
38+
"GyMMMEdhms": "E, MMM d, y G, h:mm:ss a",
39+
"MMMMEdhm": "E, MMMM d 'at' h:mm a",
40+
"hhmm": "hh:mm a",
41+
"HHmm": "HH:mm",
42+
"EHmss": "E HH:mm:ss",
43+
"MMMMh": "LLLL, h a"
44+
},
45+
de: {
46+
"yMMMMd": "d. MMMM y",
47+
"MMMMd": "d. MMMM",
48+
"MMMM": "LLLL",
49+
"MMMMy": "MMMM y",
50+
"EEEE": "cccc",
51+
"cccc": "cccc",
52+
"EEEEMMMMd": "EEEE, d. MMMM",
53+
"ccccMMMMd": "EEEE, d. MMMM",
54+
"HHmm": "HH:mm",
55+
"EEEEHHmm": "EEEE, HH:mm",
56+
"EEEEHmm": "EEEE, HH:mm",
57+
"ccccHmm": "EEEE, HH:mm",
58+
"MMMMEdhm": "E, d. MMMM 'um' h:mm a"
59+
},
60+
ru: {
61+
"yMMMMd": "d MMMM y 'г'.",
62+
"MMMMd": "d MMMM",
63+
"MMMM": "LLLL",
64+
"MMMMy": "LLLL y 'г'.",
65+
"EEEE": "cccc",
66+
"cccc": "cccc",
67+
"EEEEMMMMd": "cccc, d MMMM",
68+
"ccccMMMMd": "cccc, d MMMM",
69+
"HHmm": "HH:mm",
70+
"EEEEHHmm": "EEEE HH:mm",
71+
"EEEEHmm": "EEEE HH:mm",
72+
"ccccHHmm": "EEEE HH:mm",
73+
"ccccHmm": "EEEE HH:mm",
74+
"MMMMEdhm": "ccc, d MMMM, h:mm a"
75+
}
76+
};
77+
Object.keys( cases ).forEach( function( locale ) {
78+
Object.keys( cases[locale] ).forEach( function( skeleton ) {
79+
var expected = cases[locale][skeleton];
80+
assert.equal( expandPattern( {skeleton: skeleton}, cldrs[locale] ), expected, locale + ", " + skeleton );
81+
} );
82+
} );
2583
});
2684

2785
QUnit.test( "should expand {date: \"(full, ...)\"}", function( assert ) {

0 commit comments

Comments
 (0)