fix(common): do not round factional seconds (#24831)
fixes #24384 PR Close #24831
This commit is contained in:
parent
80576641a8
commit
a527c695aa
|
@ -29,7 +29,7 @@ enum DateType {
|
|||
Hours,
|
||||
Minutes,
|
||||
Seconds,
|
||||
Milliseconds,
|
||||
FractionalSeconds,
|
||||
Day
|
||||
}
|
||||
|
||||
|
@ -57,8 +57,6 @@ enum TranslationType {
|
|||
* If not specified, host system settings are used.
|
||||
*
|
||||
* See {@link DatePipe} for more details.
|
||||
*
|
||||
*
|
||||
*/
|
||||
export function formatDate(
|
||||
value: string | number | Date, format: string, locale: string, timezone?: string): string {
|
||||
|
@ -195,6 +193,22 @@ function padNumber(
|
|||
return neg + strNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim a fractional part to `digits` number of digits.
|
||||
* Right pads with "0" to fit the requested number of digits if needed.
|
||||
*
|
||||
* @param num The fractional part value
|
||||
* @param digits The width of the output
|
||||
*/
|
||||
function trimRPadFractional(num: number, digits: number): string {
|
||||
let strNum = String(num);
|
||||
// Add padding at the end
|
||||
while (strNum.length < digits) {
|
||||
strNum = strNum + 0;
|
||||
}
|
||||
return strNum.substr(0, digits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a date formatter that transforms a date into its locale digit representation
|
||||
*/
|
||||
|
@ -202,20 +216,26 @@ function dateGetter(
|
|||
name: DateType, size: number, offset: number = 0, trim = false,
|
||||
negWrap = false): DateFormatter {
|
||||
return function(date: Date, locale: string): string {
|
||||
let part = getDatePart(name, date, size);
|
||||
let part = getDatePart(name, date);
|
||||
if (offset > 0 || part > -offset) {
|
||||
part += offset;
|
||||
}
|
||||
if (name === DateType.Hours && part === 0 && offset === -12) {
|
||||
part = 12;
|
||||
|
||||
if (name === DateType.Hours) {
|
||||
if (part === 0 && offset === -12) {
|
||||
part = 12;
|
||||
}
|
||||
} else if (name === DateType.FractionalSeconds) {
|
||||
return trimRPadFractional(part, size);
|
||||
}
|
||||
return padNumber(
|
||||
part, size, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign), trim, negWrap);
|
||||
|
||||
const localeMinus = getLocaleNumberSymbol(locale, NumberSymbol.MinusSign);
|
||||
return padNumber(part, size, localeMinus, trim, negWrap);
|
||||
};
|
||||
}
|
||||
|
||||
function getDatePart(name: DateType, date: Date, size: number): number {
|
||||
switch (name) {
|
||||
function getDatePart(part: DateType, date: Date): number {
|
||||
switch (part) {
|
||||
case DateType.FullYear:
|
||||
return date.getFullYear();
|
||||
case DateType.Month:
|
||||
|
@ -228,13 +248,12 @@ function getDatePart(name: DateType, date: Date, size: number): number {
|
|||
return date.getMinutes();
|
||||
case DateType.Seconds:
|
||||
return date.getSeconds();
|
||||
case DateType.Milliseconds:
|
||||
const div = size === 1 ? 100 : (size === 2 ? 10 : 1);
|
||||
return Math.round(date.getMilliseconds() / div);
|
||||
case DateType.FractionalSeconds:
|
||||
return date.getMilliseconds();
|
||||
case DateType.Day:
|
||||
return date.getDay();
|
||||
default:
|
||||
throw new Error(`Unknown DateType value "${name}".`);
|
||||
throw new Error(`Unknown DateType value "${part}".`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,16 +580,15 @@ function getDateFormatter(format: string): DateFormatter|null {
|
|||
formatter = dateGetter(DateType.Seconds, 2);
|
||||
break;
|
||||
|
||||
// Fractional second padded (0-9)
|
||||
// Fractional second
|
||||
case 'S':
|
||||
formatter = dateGetter(DateType.Milliseconds, 1);
|
||||
formatter = dateGetter(DateType.FractionalSeconds, 1);
|
||||
break;
|
||||
case 'SS':
|
||||
formatter = dateGetter(DateType.Milliseconds, 2);
|
||||
formatter = dateGetter(DateType.FractionalSeconds, 2);
|
||||
break;
|
||||
// = millisecond
|
||||
case 'SSS':
|
||||
formatter = dateGetter(DateType.Milliseconds, 3);
|
||||
formatter = dateGetter(DateType.FractionalSeconds, 3);
|
||||
break;
|
||||
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ describe('Format date', () => {
|
|||
|
||||
// Check the transformation of a date into a pattern
|
||||
function expectDateFormatAs(date: Date | string, pattern: any, output: string): void {
|
||||
expect(formatDate(date, pattern, defaultLocale)).toEqual(output);
|
||||
expect(formatDate(date, pattern, defaultLocale)).toEqual(output, `pattern: "${pattern}"`);
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
|
@ -105,7 +105,7 @@ describe('Format date', () => {
|
|||
mm: '03',
|
||||
s: '1',
|
||||
ss: '01',
|
||||
S: '6',
|
||||
S: '5',
|
||||
SS: '55',
|
||||
SSS: '550',
|
||||
a: 'AM',
|
||||
|
@ -233,7 +233,6 @@ describe('Format date', () => {
|
|||
Object.keys(dateFixtures).forEach((pattern: string) => {
|
||||
expectDateFormatAs(date, pattern, dateFixtures[pattern]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should format with pattern aliases', () => {
|
||||
|
@ -266,14 +265,13 @@ describe('Format date', () => {
|
|||
() => expect(formatDate('2017-01-20T12:00:00+0000', defaultFormat, defaultLocale))
|
||||
.toEqual('Jan 20, 2017'));
|
||||
|
||||
// test for the following bugs:
|
||||
// https://github.com/angular/angular/issues/9524
|
||||
// https://github.com/angular/angular/issues/9524
|
||||
it('should format correctly with iso strings that contain time',
|
||||
() => expect(formatDate('2017-05-07T22:14:39', 'dd-MM-yyyy HH:mm', defaultLocale))
|
||||
.toMatch(/07-05-2017 \d{2}:\d{2}/));
|
||||
|
||||
// test for issue https://github.com/angular/angular/issues/21491
|
||||
// https://github.com/angular/angular/issues/21491
|
||||
it('should not assume UTC for iso strings in Safari if the timezone is not defined', () => {
|
||||
// this test only works if the timezone is not in UTC
|
||||
// which is the case for BrowserStack when we test Safari
|
||||
|
@ -283,7 +281,6 @@ describe('Format date', () => {
|
|||
}
|
||||
});
|
||||
|
||||
// test for the following bugs:
|
||||
// https://github.com/angular/angular/issues/16624
|
||||
// https://github.com/angular/angular/issues/17478
|
||||
it('should show the correct time when the timezone is fixed', () => {
|
||||
|
@ -311,5 +308,17 @@ describe('Format date', () => {
|
|||
expect(() => formatDate(date, 'b', 'de'))
|
||||
.toThrowError(/Missing extra locale data for the locale "de"/);
|
||||
});
|
||||
|
||||
// https://github.com/angular/angular/issues/24384
|
||||
it('should not round fractional seconds', () => {
|
||||
expect(formatDate(3999, 'm:ss', 'en')).toEqual('0:03');
|
||||
expect(formatDate(3999, 'm:ss.S', 'en')).toEqual('0:03.9');
|
||||
expect(formatDate(3999, 'm:ss.SS', 'en')).toEqual('0:03.99');
|
||||
expect(formatDate(3999, 'm:ss.SSS', 'en')).toEqual('0:03.999');
|
||||
expect(formatDate(3000, 'm:ss', 'en')).toEqual('0:03');
|
||||
expect(formatDate(3000, 'm:ss.S', 'en')).toEqual('0:03.0');
|
||||
expect(formatDate(3000, 'm:ss.SS', 'en')).toEqual('0:03.00');
|
||||
expect(formatDate(3000, 'm:ss.SSS', 'en')).toEqual('0:03.000');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue