Skip to content

Commit 93ac021

Browse files
feat: support for k and K date pattern specifiers
1 parent 58a0fe4 commit 93ac021

File tree

6 files changed

+142
-4
lines changed

6 files changed

+142
-4
lines changed

docs/date-formatting/index.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,32 @@ The following specifiers can be used in the custom formats.
223223

224224
formatDate(new Date(2000, 0, 1, 13), "HH:mm"); // 13:00
225225

226+
* **The `"k"` specifier**—Renders the hour using a 24-hour clock from 1 to 24.
227+
228+
To show the minimum number of digits, use `"k"`. To always show two digits, use `"kk"`.
229+
230+
import { formatDate } from '@telerik/kendo-intl';
231+
232+
formatDate(new Date(2000, 0, 1, 0), "k"); // 24
233+
234+
formatDate(new Date(2000, 0, 1, 1), "k"); // 1
235+
236+
formatDate(new Date(2000, 0, 1, 1), "kk"); // 01
237+
238+
* **The `"K"` specifier**—Renders the hour using a 12-hour clock from 0 to 11.
239+
240+
To show the minimum number of digits, use `"K"`. To always show two digits, use `"KK"`.
241+
242+
import { formatDate } from '@telerik/kendo-intl';
243+
244+
formatDate(new Date(2000, 0, 1, 0), "K a"); // 0 AM
245+
246+
formatDate(new Date(2000, 0, 1, 1), "K a"); // 1 AM
247+
248+
formatDate(new Date(2000, 0, 1, 1), "KK a"); // 01 AM
249+
250+
formatDate(new Date(2000, 0, 1, 13), "KK a"); // 01 PM
251+
226252
* **The `"m"` specifier**—Renders the minutes from 0 through 59.
227253

228254
To show the minimum number of digits, use `"m"`. To always show two digits, use `"mm"`.

src/dates/constants.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const DATE_FIELD_MAP = {
1717
'e': WEEKDAY,
1818
'h': HOUR,
1919
'H': HOUR,
20+
'k': HOUR,
21+
'K': HOUR,
2022
'm': 'minute',
2123
's': 'second',
2224
'a': 'dayperiod',
@@ -26,6 +28,6 @@ const DATE_FIELD_MAP = {
2628
'Z': ZONE
2729
};
2830

29-
const dateFormatRegExp = /d{1,2}|E{1,6}|e{1,6}|c{3,6}|c{1}|M{1,5}|L{1,5}|y{1,4}|H{1,2}|h{1,2}|m{1,2}|a{1,5}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|x{1,5}|X{1,5}|G{1,5}|q{1,5}|Q{1,5}|"[^"]*"|'[^']*'/g;
31+
const dateFormatRegExp = /d{1,2}|E{1,6}|e{1,6}|c{3,6}|c{1}|M{1,5}|L{1,5}|y{1,4}|H{1,2}|h{1,2}|k{1,2}|K{1,2}|m{1,2}|a{1,5}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|x{1,5}|X{1,5}|G{1,5}|q{1,5}|Q{1,5}|"[^"]*"|'[^']*'/g;
3032

3133
export { dateFormatRegExp, DATE_FIELD_MAP };

src/dates/format-date.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@ formatters.H = function(date, formatLength) {
103103
return pad(date.getHours(), formatLength);
104104
};
105105

106+
formatters.k = function(date, formatLength) {
107+
return pad(date.getHours() || 24, formatLength);
108+
};
109+
110+
formatters.K = function(date, formatLength) {
111+
return pad(date.getHours() % 12, formatLength);
112+
};
113+
106114
formatters.m = function(date, formatLength) {
107115
return pad(date.getMinutes(), formatLength);
108116
};

src/dates/parse-date.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,23 @@ parsers.h = function(state) {
248248
state.hours = hours;
249249
};
250250

251+
parsers.K = function(state) {
252+
lookAhead("K", state);
253+
254+
let hours = getNumber(2, state);
255+
256+
if (hours === null || outOfRange(hours, 0, 11)) {
257+
return true;
258+
}
259+
260+
state.hours = hours;
261+
};
262+
251263
parsers.a = function(state, info) {
252264
const count = lookAhead("a", state);
253265
let periodFormats = formatNames(info, "dayPeriods", count, false, true);
254266

255-
const pmHour = getIndexByName([ periodFormats.pm ], state,true);
267+
const pmHour = getIndexByName([ periodFormats.pm ], state, true);
256268
if (!pmHour && !getIndexByName([ periodFormats.am ], state, true)) {
257269
return true;
258270
}
@@ -269,6 +281,18 @@ parsers.H = function(state) {
269281
state.hours = hours;
270282
};
271283

284+
parsers.k = function(state) {
285+
lookAhead("k", state);
286+
287+
let hours = getNumber(2, state);
288+
289+
if (hours === null || outOfRange(hours, 1, 24)) {
290+
return true;
291+
}
292+
293+
state.hours = hours === 24 ? 0 : hours;
294+
};
295+
272296
parsers.m = function(state) {
273297
lookAhead("m", state);
274298
const minutes = getNumber(2, state);

src/dates/split-date-format.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ function addLiteral(parts, value) {
5454
}
5555

5656
function isHour12(pattern) {
57-
return pattern === 'h';
57+
return pattern === 'h' || pattern === 'K';
5858
}
5959

6060
export default function splitDateFormat(format, locale = DEFAULT_LOCALE) {

test/dates.js

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,23 @@ describe('date formatting', () => {
158158
expect(formatDate(date(2000, 1, 1, 12), "hh:mm")).toEqual("12:00");
159159
});
160160

161+
it('supports 0-11 hour clock formatting', () => {
162+
const hourZero = date(2000, 1, 1, 0);
163+
const hourSmall = date(2000, 1, 1, 1);
164+
const hour12 = date(2000, 1, 1, 12);
165+
const hourBig = date(2000, 1, 1, 13);
166+
167+
expect(formatDate(hourZero, "K:mm")).toEqual("0:00");
168+
expect(formatDate(hourSmall, "K:mm")).toEqual("1:00");
169+
expect(formatDate(hour12, "K:mm")).toEqual("0:00");
170+
expect(formatDate(hourBig, "K:mm")).toEqual("1:00");
171+
172+
expect(formatDate(hourZero, "KK:mm")).toEqual("00:00");
173+
expect(formatDate(hourSmall, "KK:mm")).toEqual("01:00");
174+
expect(formatDate(hour12, "KK:mm")).toEqual("00:00");
175+
expect(formatDate(hourBig, "KK:mm")).toEqual("01:00");
176+
});
177+
161178
it('supports 24-hour clock formatting', () => {
162179
const hourSmall = date(2000, 1, 1, 1);
163180
const hourBig = date(2000, 1, 1, 23);
@@ -168,6 +185,23 @@ describe('date formatting', () => {
168185
expect(formatDate(hourBig, "HH:mm")).toEqual("23:00");
169186
});
170187

188+
it('supports 1-24 hour clock formatting', () => {
189+
const hourZero = date(2000, 1, 1, 0);
190+
const hourSmall = date(2000, 1, 1, 1);
191+
const hour12 = date(2000, 1, 1, 12);
192+
const hourBig = date(2000, 1, 1, 13);
193+
194+
expect(formatDate(hourZero, "k:mm")).toEqual("24:00");
195+
expect(formatDate(hourSmall, "k:mm")).toEqual("1:00");
196+
expect(formatDate(hour12, "k:mm")).toEqual("12:00");
197+
expect(formatDate(hourBig, "k:mm")).toEqual("13:00");
198+
199+
expect(formatDate(hourZero, "kk:mm")).toEqual("24:00");
200+
expect(formatDate(hourSmall, "kk:mm")).toEqual("01:00");
201+
expect(formatDate(hour12, "kk:mm")).toEqual("12:00");
202+
expect(formatDate(hourBig, "kk:mm")).toEqual("13:00");
203+
});
204+
171205
it('supports day period short formatting', () => {
172206
expect(formatDate(date(2000, 1, 1, 1), "hh a")).toEqual("01 AM");
173207
expect(formatDate(date(2000, 1, 1, 13), "hh a")).toEqual("01 PM");
@@ -1115,6 +1149,42 @@ describe('date parsing', () => {
11151149

11161150
expect(parseDate("2014-05-21 00:00:00Z", "yyyy-MM-dd HH:mm:ssX")).toEqual(utcDate);
11171151
});
1152+
1153+
it('parses 0-11 hour clock formatted value', () => {
1154+
const hourZero = date(2000, 1, 1, 0);
1155+
const hourSmall = date(2000, 1, 1, 1);
1156+
const hour12 = date(2000, 1, 1, 12);
1157+
const hourBig = date(2000, 1, 1, 13);
1158+
1159+
expect(parseDate("01.01.2000 0:00 am", "dd.MM.yyyy K:mm a")).toEqual(hourZero);
1160+
expect(parseDate("01.01.2000 1:00 am", "dd.MM.yyyy K:mm a")).toEqual(hourSmall);
1161+
expect(parseDate("01.01.2000 0:00 pm", "dd.MM.yyyy K:mm a")).toEqual(hour12);
1162+
expect(parseDate("01.01.2000 1:00 pm", "dd.MM.yyyy K:mm a")).toEqual(hourBig);
1163+
1164+
expect(parseDate("01.01.2000 00:00 am", "dd.MM.yyyy KK:mm a")).toEqual(hourZero);
1165+
expect(parseDate("01.01.2000 01:00 am", "dd.MM.yyyy KK:mm a")).toEqual(hourSmall);
1166+
expect(parseDate("01.01.2000 00:00 pm", "dd.MM.yyyy KK:mm a")).toEqual(hour12);
1167+
expect(parseDate("01.01.2000 01:00 pm", "dd.MM.yyyy KK:mm a")).toEqual(hourBig);
1168+
});
1169+
1170+
it('parses 1-24 hour clock formatted value', () => {
1171+
const hourZero = date(2000, 1, 1, 0);
1172+
const hourSmall = date(2000, 1, 1, 1);
1173+
const hour12 = date(2000, 1, 1, 12);
1174+
const hourBig = date(2000, 1, 1, 13);
1175+
1176+
expect(parseDate("01.01.2000 0:00", "dd.MM.yyyy k:mm")).toBeNull();
1177+
expect(parseDate("01.01.2000 24:00", "dd.MM.yyyy k:mm")).toEqual(hourZero);
1178+
expect(parseDate("01.01.2000 1:00", "dd.MM.yyyy k:mm")).toEqual(hourSmall);
1179+
expect(parseDate("01.01.2000 12:00", "dd.MM.yyyy k:mm")).toEqual(hour12);
1180+
expect(parseDate("01.01.2000 13:00", "dd.MM.yyyy k:mm")).toEqual(hourBig);
1181+
1182+
expect(parseDate("01.01.2000 00:00", "dd.MM.yyyy kk:mm")).toBeNull();
1183+
expect(parseDate("01.01.2000 24:00", "dd.MM.yyyy kk:mm")).toEqual(hourZero);
1184+
expect(parseDate("01.01.2000 01:00", "dd.MM.yyyy kk:mm")).toEqual(hourSmall);
1185+
expect(parseDate("01.01.2000 12:00", "dd.MM.yyyy kk:mm")).toEqual(hour12);
1186+
expect(parseDate("01.01.2000 13:00", "dd.MM.yyyy kk:mm")).toEqual(hourBig);
1187+
});
11181188
});
11191189

11201190
describe('splitDateFormat', () => {
@@ -1349,9 +1419,17 @@ describe('splitDateFormat', () => {
13491419
type: 'hour',
13501420
pattern: 'H',
13511421
hour12: false
1422+
}, {
1423+
type: 'hour',
1424+
pattern: 'k',
1425+
hour12: false
1426+
}, {
1427+
type: 'hour',
1428+
pattern: 'K',
1429+
hour12: true
13521430
}];
13531431

1354-
expect(splitDateFormat('hH')).toEqual(expected);
1432+
expect(splitDateFormat('hHkK')).toEqual(expected);
13551433
});
13561434
});
13571435

0 commit comments

Comments
 (0)