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

Date: Add fractional seconds support in formatters #763

Merged
merged 6 commits into from
Jul 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,8 @@ module.exports = function( grunt ) {
.replace( /define\(\[[^\]]+\]\)[\W\n]+$/, "" ); /* 3 */

// Type b (not as simple as a single return)
if ( [ "util/globalize-date" ].indexOf( id ) !== -1 ) {
contents = "var " + name[ 0 ].toUpperCase() +
name.slice( 1 ) + " = (function() {" +
contents + "}());";
if ( [ "expand-pattern/augment-format" ].indexOf( id ) !== -1 ) {
contents = "var " + name + " = (function() {" + contents + "}());";

// Type a (single return)
} else if ( ( /\// ).test( id ) ) {
Expand Down
47 changes: 35 additions & 12 deletions src/date/expand-pattern/augment-format.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,53 @@ define([
"../../util/string/repeat"
], function( dateExpandPatternNormalizePatternType, datePatternRe, stringRepeat ) {

return function( requestedSkeleton, bestMatchFormat ) {
var i, j, matchedType, matchedLength, requestedType, requestedLength,
function expandBestMatchFormat( skeletonWithoutFractionalSeconds, bestMatchFormat ) {
var i, j, bestMatchFormatParts, matchedType, matchedLength, requestedType,
requestedLength, requestedSkeletonParts,

// Using an easier to read variable.
normalizePatternType = dateExpandPatternNormalizePatternType;

requestedSkeleton = requestedSkeleton.match( datePatternRe );
bestMatchFormat = bestMatchFormat.match( datePatternRe );
requestedSkeletonParts = skeletonWithoutFractionalSeconds.match( datePatternRe );
bestMatchFormatParts = bestMatchFormat.match( datePatternRe );

for ( i = 0; i < bestMatchFormat.length; i++ ) {
matchedType = bestMatchFormat[i].charAt( 0 );
matchedLength = bestMatchFormat[i].length;
for ( j = 0; j < requestedSkeleton.length; j++ ) {
requestedType = requestedSkeleton[j].charAt( 0 );
requestedLength = requestedSkeleton[j].length;
for ( i = 0; i < bestMatchFormatParts.length; i++ ) {
matchedType = bestMatchFormatParts[i].charAt( 0 );
matchedLength = bestMatchFormatParts[i].length;
for ( j = 0; j < requestedSkeletonParts.length; j++ ) {
requestedType = requestedSkeletonParts[j].charAt( 0 );
requestedLength = requestedSkeletonParts[j].length;
if ( normalizePatternType( matchedType ) === normalizePatternType( requestedType ) &&
matchedLength < requestedLength
) {
bestMatchFormat[i] = stringRepeat( matchedType, requestedLength );
bestMatchFormatParts[i] = stringRepeat( matchedType, requestedLength );
}
}
}

return bestMatchFormat.join( "" );
return bestMatchFormatParts.join( "" );
}

// See: http://www.unicode.org/reports/tr35/tr35-dates.html#Matching_Skeletons
return function( requestedSkeleton, bestMatchFormat, decimalSeparator ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rxaviers how about this? Same file, two functions. Encapsulates all the "adjustments" to the bestMatchFormat

Copy link
Member

Choose a reason for hiding this comment

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

It's good except for our build process, which assumes all files have one export (and no outer code). In order to have something different, we need an update the onBuildWrite, specifically tell it this file is a "type b".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it. There's a problem though: if I make it a "type b", that capitalizes the first character of the variable name, which breaks the output, as the actual variable name does not have a capital first letter. Example output:

var DateExpandPatternAugmentFormat = (function() {
function expandBestMatchFormat( skeletonWithoutFractionalSeconds, bestMatchFormat ) {
    ...
}

// See: http://www.unicode.org/reports/tr35/tr35-dates.html#Matching_Skeletons
return function( requestedSkeleton, bestMatchFormat, decimalSeparator ) {
    ...
    bestMatchFormat = expandBestMatchFormat( skeletonWithoutFractionalSeconds, bestMatchFormat );
    ...
};

}());

Why does it capitalize the first letter in DateExpandPatternAugmentFormat? The only other "type b" is "util/globalize-date", but that file doesn't seem to exist anymore, so I can't look at the example to know what the intention of the capitalization is.

However, if I leave it as a "type a", everything still works. This is the output:

function expandBestMatchFormat( skeletonWithoutFractionalSeconds, bestMatchFormat ) {
    ...
}

var dateExpandPatternAugmentFormat = function( requestedSkeleton, bestMatchFormat, decimalSeparator ) {
    ...
    bestMatchFormat = expandBestMatchFormat( skeletonWithoutFractionalSeconds, bestMatchFormat );
    ...
};

This works just fine.

So, what should I do here?

  1. Leave as a type a
  2. Change how the build handles type b so it stops capitalizing. If I do this should I also remove the reference to util/globalize-date?
  3. Something else? Move the other function to another file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Number 2. (sorry for the delay)

Yeap, existing "type b" is bugged. Let's fix it by stop capitalizing the variable and by also removing the reference to the non-existing util/globalize-date. Please, take a look at this old-but-correct "type b" implementation: here and here.

Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

var countOfFractionalSeconds, fractionalSecondMatch, lastSecondIdx,
skeletonWithoutFractionalSeconds;

fractionalSecondMatch = requestedSkeleton.match( /S/g );
countOfFractionalSeconds = fractionalSecondMatch ? fractionalSecondMatch.length : 0;
skeletonWithoutFractionalSeconds = requestedSkeleton.replace( /S/g, "" );

bestMatchFormat = expandBestMatchFormat( skeletonWithoutFractionalSeconds, bestMatchFormat );

lastSecondIdx = bestMatchFormat.lastIndexOf( "s" );
if ( lastSecondIdx !== -1 && countOfFractionalSeconds !== 0 ) {
bestMatchFormat =
bestMatchFormat.slice( 0, lastSecondIdx + 1 ) +
decimalSeparator +
stringRepeat( "S", countOfFractionalSeconds ) +
bestMatchFormat.slice( lastSecondIdx + 1 );
}
return bestMatchFormat;
};

});
10 changes: 6 additions & 4 deletions src/date/expand-pattern/get-best-match-pattern.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
define([
"./augment-format",
"./compare-formats"
], function( dateExpandPatternAugmentFormat, dateExpandPatternCompareFormats ) {
"./compare-formats",
"../../number/symbol"
], function( dateExpandPatternAugmentFormat, dateExpandPatternCompareFormats, numberSymbol ) {

return function( cldr, askedSkeleton ) {
var availableFormats, pattern, ratedFormats, skeleton,
var availableFormats, decimalSeparator, pattern, ratedFormats, skeleton,
path = "dates/calendars/gregorian/dateTimeFormats/availableFormats",

// Using easier to read variables.
Expand Down Expand Up @@ -34,7 +35,8 @@ return function( cldr, askedSkeleton ) {
});

if ( ratedFormats.length ) {
pattern = augmentFormat( askedSkeleton, ratedFormats[0].pattern );
decimalSeparator = numberSymbol( "decimal", cldr );
pattern = augmentFormat( askedSkeleton, ratedFormats[0].pattern, decimalSeparator );
}
}

Expand Down
1 change: 1 addition & 0 deletions test/compiler/cases/date.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module.exports = {
{ formatter: Globalize.dateFormatter({ skeleton: "GyMMMEd" }), args: [ date ] },
{ formatter: Globalize.dateFormatter({ skeleton: "dhms" }), args: [ date ] },
{ formatter: Globalize.dateFormatter({ skeleton: "GyMMMEdhms" }), args: [ date ] },
{ formatter: Globalize.dateFormatter({ skeleton: "GyMMMEdhmsSSS" }), args: [ date ] },
{ formatter: Globalize.dateFormatter({ skeleton: "Ems" }), args: [ date ] },
{ formatter: Globalize.dateFormatter({ skeleton: "yQQQhm" }), args: [ date ] },

Expand Down
1 change: 1 addition & 0 deletions test/functional/date/date-formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ QUnit.test( "should return a formatter", function( assert ) {
assert.equal( Globalize.dateFormatter({ skeleton: "GyMMMEd" })( date ), "Wed, Sep 15, 2010 AD" );
assert.equal( Globalize.dateFormatter({ skeleton: "dhms" })( date ), "15, 5:35:07 PM" );
assert.equal( Globalize.dateFormatter({ skeleton: "GyMMMEdhms" })( date ), "Wed, Sep 15, 2010 AD, 5:35:07 PM" );
assert.equal( Globalize.dateFormatter({ skeleton: "GyMMMEdhmsSSS" })( date ), "Wed, Sep 15, 2010 AD, 5:35:07.369 PM" );
assert.equal( Globalize.dateFormatter({ skeleton: "Ems" })( date ), "Wed, 35:07" );
assert.equal( Globalize.dateFormatter({ skeleton: "yQQQhm" })( date ), "Q3 2010, 5:35 PM" );
});
Expand Down
7 changes: 7 additions & 0 deletions test/functional/date/parse-date.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ QUnit.test( "should parse skeleton", function( assert ) {
date = startOf( date, "second" );
assertParseDate( assert, "Wed 5:35:07 PM", { skeleton: "Ehms" }, date );

date = new Date();
date.setHours( 17 );
date.setMinutes( 35 );
date.setSeconds( 7 );
date.setMilliseconds(734);
assertParseDate( assert, "Wed 5:35:07.734 PM", { skeleton: "EhmsSSS" }, date );

date = new Date( 2010, 8, 15 );
date = startOf( date, "day" );
assertParseDate( assert, "Wed, Sep 15, 2010 AD", { skeleton: "GyMMMEd" }, date );
Expand Down
2 changes: 2 additions & 0 deletions test/unit/date/expand-pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ QUnit.test( "should expand {skeleton: \"<skeleton>\"}", function( assert ) {
assert.expandPattern( en, { skeleton: "hhmm" }, "hh:mm a" );
assert.expandPattern( en, { skeleton: "HHmm" }, "HH:mm" );
assert.expandPattern( en, { skeleton: "EHmss" }, "E HH:mm:ss" );
assert.expandPattern( en, { skeleton: "hhmmssSS" }, "hh:mm:ss.SS a" );
assert.expandPattern( en, { skeleton: "yy" }, "yy" );
assert.expandPattern( de, { skeleton: "yMMMMd" }, "d. MMMM y" );
assert.expandPattern( de, { skeleton: "MMMM" }, "LLLL" );
Expand All @@ -56,6 +57,7 @@ QUnit.test( "should expand {skeleton: \"<skeleton>\"}", function( assert ) {
assert.expandPattern( de, { skeleton: "MMMMEEEEd" }, "EEEE, d. MMMM" );
assert.expandPattern( de, { skeleton: "MMMMccccd" }, "EEEE, d. MMMM" );
assert.expandPattern( de, { skeleton: "HHmm" }, "HH:mm" );
assert.expandPattern( de, { skeleton: "HHmmssSS" }, "HH:mm:ss,SS" );
assert.expandPattern( de, { skeleton: "EEEEHHmm" }, "EEEE, HH:mm" );
assert.expandPattern( de, { skeleton: "EEEEHmm" }, "EEEE, HH:mm" );
assert.expandPattern( de, { skeleton: "ccccHmm" }, "EEEE, HH:mm" );
Expand Down
28 changes: 15 additions & 13 deletions test/unit/date/expand-pattern/augment-format.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,31 @@ define([
QUnit.module( "Date Expand Pattern Augment Format" );

QUnit.test( "should augment date skeletons", function( assert ) {
assert.equal( augmentFormat( "yy", "y" ), "yy" );
assert.equal( augmentFormat( "yMMdd", "M/d/y" ), "MM/dd/y" );
assert.equal( augmentFormat( "yy", "y", "." ), "yy" );
assert.equal( augmentFormat( "yMMdd", "M/d/y", "." ), "MM/dd/y" );

assert.equal( augmentFormat( "MMMMd", "MMM d" ), "MMMM d" );
assert.equal( augmentFormat( "MMMMd", "M d" ), "MMMM d" );
assert.equal( augmentFormat( "MMMMd", "'M' M d" ), "'M' MMMM d" );
assert.equal( augmentFormat( "MMMMd", "MMM d", "." ), "MMMM d" );
assert.equal( augmentFormat( "MMMMd", "M d", "." ), "MMMM d" );
assert.equal( augmentFormat( "MMMMd", "'M' M d", "." ), "'M' MMMM d" );

assert.equal( augmentFormat( "LLLL", "LLL" ), "LLLL" );
assert.equal( augmentFormat( "LLLLd", "MMM d" ), "MMMM d" );
assert.equal( augmentFormat( "LLLL", "LLL", "." ), "LLLL" );
assert.equal( augmentFormat( "LLLLd", "MMM d", "." ), "MMMM d" );

assert.equal( augmentFormat( "EEEE", "ccc" ), "cccc" );
assert.equal( augmentFormat( "EEEEd", "d E" ), "d EEEE" );
assert.equal( augmentFormat( "EEEE", "ccc", "." ), "cccc" );
assert.equal( augmentFormat( "EEEEd", "d E", "."), "d EEEE" );

assert.equal( augmentFormat( "cccc", "ccc" ), "cccc" );
assert.equal( augmentFormat( "ccccd", "d E" ), "d EEEE" );
assert.equal( augmentFormat( "cccc", "ccc", "." ), "cccc" );
assert.equal( augmentFormat( "ccccd", "d E", "." ), "d EEEE" );
});

QUnit.test( "should augment time skeletons", function( assert ) {
assert.equal( augmentFormat( "hhmm", "h:mm a" ), "hh:mm a" );
assert.equal( augmentFormat( "hhmm", "h:mm a", "." ), "hh:mm a" );
assert.equal( augmentFormat( "hhmmsS", "hh:mm:ss a", "." ), "hh:mm:ss.S a" );
assert.equal( augmentFormat( "hhmmssSSS", "hh:mm:ss a", "," ), "hh:mm:ss,SSS a" );
});

QUnit.test( "should augment datetime skeletons", function( assert ) {
assert.equal( augmentFormat( "EEEhhmmss", "E h:mm:ss a" ), "EEE hh:mm:ss a" );
assert.equal( augmentFormat( "EEEhhmmss", "E h:mm:ss a", "." ), "EEE hh:mm:ss a" );
});

});
1 change: 1 addition & 0 deletions test/unit/date/expand-pattern/get-best-match-pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ QUnit.test( "should get best match pattern", function( assert ) {
assert.equal( getBestMatchPattern( en, "ccccd" ), "d EEEE" );

assert.equal( getBestMatchPattern( en, "hhmms" ), "hh:mm:ss a" );
assert.equal( getBestMatchPattern( en, "hhmmsS" ), "hh:mm:ss.S a" );
});

QUnit.test( "should be order-proof", function( assert ) {
Expand Down