Skip to content

Commit 069d890

Browse files
authored
Add Y~ and MMM~ format tokens. (#21)
1 parent 683d058 commit 069d890

5 files changed

Lines changed: 43 additions & 60 deletions

File tree

README.md

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -163,14 +163,11 @@ When dealing with Daylight Saving Time, and days when clocks are turned backward
163163

164164
By default, any ambiguous time is treated as the earlier time, the first occurrence of that time during a day. You can, however, use either an explicit UTC offset, or a subscript 2 (₂), to indicate the later time.
165165

166-
`ttime('11/7/2021 1:25 AM America/Denver', 'MM/DD/YYYY h:m a z').toString()` →<br>
167-
`DateTime<2021-11-07T01:25:00.000 -06:00§>`
166+
`ttime('11/7/2021 1:25 AM America/Denver', 'MM/DD/YYYY h:m a z').toString()` →<br>`DateTime<2021-11-07T01:25:00.000 -06:00§>`
168167

169-
`ttime('11/7/2021 1:25₂ AM America/Denver', 'MM/DD/YYYY h:m a z').toString()` →<br>
170-
`DateTime<2021-11-07T01:25:00.000₂-07:00>`
168+
`ttime('11/7/2021 1:25₂ AM America/Denver', 'MM/DD/YYYY h:m a z').toString()` →<br>`DateTime<2021-11-07T01:25:00.000₂-07:00>`
171169

172-
`ttime('2021-11-07 01:25 -07:00 America/Denver').toString()` →<br>
173-
`DateTime<2021-11-07T01:25:00.000₂-07:00>`
170+
`ttime('2021-11-07 01:25 -07:00 America/Denver').toString()` →<br>`DateTime<2021-11-07T01:25:00.000₂-07:00>`
174171

175172
## Formatting output
176173

@@ -182,11 +179,9 @@ You can also produce more customized, flexible formatting, specifying the order,
182179

183180
For example:
184181

185-
`ttime().format('ddd MMM D, y N [at] h:mm A z')` →<br>
186-
`Wed Feb 3, 2021 AD at 8:59 PM EST`
182+
`ttime().format('ddd MMM D, y N [at] h:mm A z')` →<br>`Wed Feb 3, 2021 AD at 8:59 PM EST`
187183

188-
`ttime().toLocale('de').format('ddd MMM D, y N [at] h:mm A z')` →<br>
189-
`Mi 02 3, 2021 n. Chr. at 9:43 PM GMT-5`
184+
`ttime().toLocale('de').format('ddd MMM D, y N [at] h:mm A z')` →<br>`Mi 02 3, 2021 n. Chr. at 9:43 PM GMT-5`
190185

191186
Please note that most unaccented Latin letters (a-z, A-Z) are interpreted as special formatting characters, as well as the tilde (`~`), so when using those characters as literal text they should be surrounded with square brackets, as with the word “at” in the example above.
192187

@@ -196,6 +191,12 @@ A few of the formatting tokens below can have an optional trailing tilde (`~`) a
196191

197192
For all other languages, `~` is replaced with a space character when the following character is a letter or digit, or simply removed when followed by punctuation or the end of the format string.
198193

194+
For example:
195+
196+
`ttime().toLocale('zh').format('MMM~YYYY~')` →<br>`8月2021年`
197+
198+
`ttime().toLocale('es').format('MMM~YYYY~')` →<br>`ago 2021`
199+
199200
## Format string tokens
200201

201202
| | Token | Output |
@@ -206,7 +207,7 @@ For all other languages, `~` is replaced with a space character when the followi
206207
| Year | YYYYYY | -001970 -001971 ... +001907 +001971<br><br>Always-signed years, padded to six digits. |
207208
| | YYYY&nbsp;&nbsp;<br>YYYY~ | 1970 1971 ... 2029 2030<br><br>Padded to at least four digits. With `~`, `` or `` is added when needed for CJK locales, otherwise replaced by a space character or empty string. |
208209
| | YY | 70 71 ... 29 30<br><br>Padded to two digits with leading zero if necessary. |
209-
| | Y | 1970 1971 ... 9999 +10000 +10001<br><br>Padded to at least four digits, `+` sign shown when over 9999. |
210+
| | Y&nbsp;&nbsp;<br>Y~ | 1970 1971 ... 9999 +10000 +10001<br><br>Padded to at least four digits, `+` sign shown when over 9999. With `~`, `` or `` is added when needed for CJK locales, otherwise `~` is replaced by a space character or empty string. |
210211
| | y&nbsp;&nbsp;<br>y~ | 1 2 ... 2020 ...<br><br>Era year, for use with BC/AD, never 0 or negative. With `~`, `` or `` is added when needed for CJK locales, otherwise `~` is replaced by a space character or empty string. |
211212
| Week year (ISO) | GGGG | 1970 1971 ... 2029 2030, `+` sign shown when over 9999. |
212213
| | GG | 70 71 ... 29 30<br><br>Padded to two digits with leading zero if necessary. |
@@ -215,9 +216,9 @@ For all other languages, `~` is replaced with a space character when the followi
215216
| Quarter | Qo | 1st 2nd 3rd 4th |
216217
| | Q | 1 2 3 4 |
217218
| Month | MMMM&nbsp;&nbsp;<br>MMMM~ | January February ... November December<br>1月 2月 ... 11月 12月 • 一月 二月 ... 十一月 十二月 • 1월 2월 ... 11월 12월<br><br>For CJK locales, `` or `` is added when using either the `MMMM` and `MMMM~` token, but using `MMMM~` allows the position of the `~` to be replaced with a blank, when appropriate, for other languages. |
218-
| | MMM | Jan Feb ... Nov Dec |
219-
| | MM&nbsp;&nbsp;<br>MM~ | 01 02 ... 11 12<br><br>With `~`, `` or `` is added when needed for CJK locales, otherwise `~` is replaced by a space character or empty string. |
220-
| | M&nbsp;&nbsp;<br>M~ | 1 2 ... 11 12<br><br>With `~`, `` or `` is added when needed for CJK locales, otherwise `~` is replaced by a space character or empty string. |
219+
| | MMM&nbsp;&nbsp;<br>MMM~ | Jan Feb ... Nov Dec<br>1月 2月 ... 11月 12月 • 1월 2월 ... 11월 12월<br><br>With `~`, `` or `` is added when needed for CJK locales, otherwise `~` is replaced by a space character or empty string. |
220+
| | MM&nbsp;&nbsp;<br>MM~ | 01 02 ... 11 12<br>01月 02月 ... 11月 12月 • 01월 02월 ... 11월 12월<br><br>With `~`, `` or `` is added when needed for CJK locales, otherwise `~` is replaced by a space character or empty string. |
221+
| | M&nbsp;&nbsp;<br>M~ | 1 2 ... 11 12<br>1月 2月 ... 11月 12月 • 1월 2월 ... 11월 12월<br><br>With `~`, `` or `` is added when needed for CJK locales, otherwise `~` is replaced by a space character or empty string. |
221222
| | Mo | 1st 2nd ... 11th 12th |
222223
| Week (ISO) | WW | 01 02 ... 52 53 |
223224
| | W | 1 2 ... 52 53 |
@@ -342,28 +343,21 @@ ttime.MONTH = 'Y-MM';
342343

343344
## Converting timezones
344345

345-
`ttime('2005-10-10 16:30 America/Los_Angeles').tz('Europe/Warsaw').toString()` →<br>
346-
`DateTime<2005-10-11T01:30:00.000 +02:00>`
346+
`ttime('2005-10-10 16:30 America/Los_Angeles').tz('Europe/Warsaw').toString()` →<br>`DateTime<2005-10-11T01:30:00.000 +02:00>`
347347

348348
Please note that if you pass a second argument of `true`, the timezone is changed, _but the wall time stays the same._ This same option to preserve wall time is available for the `utc()` and `local()` methods, where the optional boolean value will be the one and only argument.
349349

350-
`ttime('2005-10-10 16:30 America/Los_Angeles').tz('Europe/Warsaw', true).toString()` →<br>
351-
`DateTime<2005-10-10T16:30:00.000 +02:00>`
350+
`ttime('2005-10-10 16:30 America/Los_Angeles').tz('Europe/Warsaw', true).toString()` →<br>`DateTime<2005-10-10T16:30:00.000 +02:00>`
352351

353-
`ttime('2005-10-10 16:30 America/Los_Angeles').utc().toString()` →<br>
354-
`DateTime<2005-10-10T23:30:00.000 +00:00>`
352+
`ttime('2005-10-10 16:30 America/Los_Angeles').utc().toString()` →<br>`DateTime<2005-10-10T23:30:00.000 +00:00>`
355353

356-
`ttime('2005-10-10 16:30 America/Los_Angeles').utc().toString(true)` →<br>
357-
`DateTime<2005-10-10T16:30:00.000 +00:00>`
354+
`ttime('2005-10-10 16:30 America/Los_Angeles').utc().toString(true)` →<br>`DateTime<2005-10-10T16:30:00.000 +00:00>`
358355

359-
`// Local zone is America/New_York`<br>
360-
`ttime('2005-10-10 16:30 America/Los_Angeles').local().toString()` →<br>
361-
`DateTime<2005-10-10T19:30:00.000 +04:00>`
356+
`// Local zone is America/New_York`<br>`ttime('2005-10-10 16:30 America/Los_Angeles').local().toString()` →<br>`DateTime<2005-10-10T19:30:00.000 +04:00>`
362357

363358
## Converting locales
364359

365-
`ttime('7. helmikuuta 2021', 'IL', 'fi').toLocale('de').format('IL')` →<br>
366-
`7. Februar 2021`
360+
`ttime('7. helmikuuta 2021', 'IL', 'fi').toLocale('de').format('IL')` →<br>`7. Februar 2021`
367361

368362
## Defining and updating timezones
369363

@@ -586,21 +580,18 @@ For fields `MILLI` through `HOUR`, fixed units of time, multiplied by the `amoun
586580

587581
DST can alter the duration of days, typically adding or subtracting an hour, but other amounts of change are possible (like the half-hour shift used by Australias Lord Howe Island), so adding days can possibly cause the hour (and even minute) fields to change:
588582

589-
`ttime('2021-02-28T07:00 Europe/London', false).add('days', 100).toIsoString()`<br>
590-
`2021-06-08T08:00:00.000+01:00` (note shift from 7:00 to 8:00)
583+
`ttime('2021-02-28T07:00 Europe/London', false).add('days', 100).toIsoString()` →<br>`2021-06-08T08:00:00.000+01:00` (note shift from 7:00 to 8:00)
591584

592585
`ttime('2021-02-28T07:00 Australia/Lord_Howe, false').add('days', 100).toIsoString()`<br>
593-
`2021-06-08T06:30:00.000+10:30` (note shift from 7:00 to 6:30)
586+
2021-06-08T06:30:00.000+10:30` (note shift from 7:00 to 6:30)
594587
595588
By default, however, hour and minute fields remain unchanged.
596589
597-
`ttime('2021-02-28T07:00 Australia/Lord_Howe').add('days', 100).toIsoString()`<br>
598-
`2021-06-08T07:00:00.000+10:30`
590+
`ttime('2021-02-28T07:00 Australia/Lord_Howe').add('days', 100).toIsoString()` →<br>`2021-06-08T07:00:00.000+10:30`
599591
600592
Even with the default behavior, however, it is still possible for hours and minutes to change, in just the same way adding one month to January 31 does not yield February 31. When clocks are turned forward, some times of day simply do not exist, so a result might have to be adjusted to a valid hour and minute in some cases.
601593
602-
`ttime('2000-04-27T00:30 Africa/Cairo').add('day', 1).toString()`<br>
603-
`DateTime<2000-04-28T01:30:00.000 +03:00§>` (clock turned forward at midnight to 1:00)
594+
`ttime('2000-04-27T00:30 Africa/Cairo').add('day', 1).toString()` →<br>`DateTime<2000-04-28T01:30:00.000 +03:00§>` (clock turned forward at midnight to 1:00)
604595
605596
### Using `roll()`
606597
@@ -635,23 +626,17 @@ There is a corresponding `get()` method which returns the numeric value of a fie
635626
636627
These functions transform a `DateTime` to the beginning or end of a given unit of time.
637628
638-
`ttime('2300-05-05T04:08:10.909').startOf(DateTimeField.MINUTE).toIsoString(23)` →<br>
639-
`2300-05-05T04:08:00.000`
629+
`ttime('2300-05-05T04:08:10.909').startOf(DateTimeField.MINUTE).toIsoString(23)` →<br>`2300-05-05T04:08:00.000`
640630
641-
`ttime('2300-05-05T04:08:10.909').startOf('hour').toIsoString(23)` →<br>
642-
`2300-05-05T04:00:00.000`
631+
`ttime('2300-05-05T04:08:10.909').startOf('hour').toIsoString(23)` →<br>`2300-05-05T04:00:00.000`
643632
644-
`ttime('2300-05-05T04:08:10.909').startOf(DateTimeField.WEEK).format(ttime.WEEK_AND_DAY)` →<br>
645-
`2300-W18-1`
633+
`ttime('2300-05-05T04:08:10.909').startOf(DateTimeField.WEEK).format(ttime.WEEK_AND_DAY)` →<br>`2300-W18-1`
646634
647-
`ttime('2300-05-05T04:08:10.909').startOf('year').toIsoString(23)` →<br>
648-
`2300-01-01T00:00:00.000`
635+
`ttime('2300-05-05T04:08:10.909').startOf('year').toIsoString(23)` →<br>`2300-01-01T00:00:00.000`
649636
650-
`ttime('2300-05-05T04:08:10.909').endOf('day').toIsoString(23)` →<br>
651-
`2300-05-05T23:59:59.999`
637+
`ttime('2300-05-05T04:08:10.909').endOf('day').toIsoString(23)` →<br>`2300-05-05T23:59:59.999`
652638
653-
`ttime('2300-05-05T04:08:10.909').endOf(DateTimeField.MONTH).toIsoString(23)` →<br>
654-
`2300-05-31T23:59:59.999`
639+
`ttime('2300-05-05T04:08:10.909').endOf(DateTimeField.MONTH).toIsoString(23)` →<br>`2300-05-31T23:59:59.999`
655640
656641
## Time value
657642
@@ -905,23 +890,19 @@ getDiscontinuityDuringDay(yearOrDate?: YearOrDate, month?: number, day?: number)
905890

906891
### Typical Daylight Saving Time examples
907892

908-
`new DateTime('2021-03-14', 'America/New_York').getDiscontinuityDuringDay()` →<br>
909-
`{ start: '02:00:00', end: '03:00:00', delta: 3600000 } // spring forward!`
893+
`new DateTime('2021-03-14', 'America/New_York').getDiscontinuityDuringDay()` →<br>`{ start: '02:00:00', end: '03:00:00', delta: 3600000 } // spring forward!`
910894

911895
`new DateTime('2021-07-01', 'America/New_York').getDiscontinuityDuringDay()`) → `null`
912896

913-
`new DateTime('2021-11-07', 'America/New_York').getDiscontinuityDuringDay()`<br>
914-
`{ start: '02:00:00', end: '01:00:00', delta: -3600000 } // fall back!`
897+
`new DateTime('2021-11-07', 'America/New_York').getDiscontinuityDuringDay()` →<br>`{ start: '02:00:00', end: '01:00:00', delta: -3600000 } // fall back!`
915898

916899
### Examples of big UTC offset shifts due to moving the International Dateline
917900

918901
`// As soon as it’s midnight on the 30th, it’s instantly midnight on the 31st, erasing 24 hours:`<br>
919-
`new DateTime('2011-12-30', 'Pacific/Apia').getDiscontinuityDuringDay()`) →<br>
920-
`{ start: '00:00:00', end: '24:00:00', delta: 86400000 }`
902+
`new DateTime('2011-12-30', 'Pacific/Apia').getDiscontinuityDuringDay()`) →<br>`{ start: '00:00:00', end: '24:00:00', delta: 86400000 }`
921903

922904
`// As soon as it’s midnight on the 31th, turn back to 1AM on the 30th, adding 23 hours to the day:`<br>
923-
`new DateTime('1969-09-30', 'Pacific/Kwajalein').getDiscontinuityDuringDay()`<br>
924-
`{ start: '24:00:00', end: '01:00:00', delta: -82800000 }`
905+
`new DateTime('1969-09-30', 'Pacific/Kwajalein').getDiscontinuityDuringDay()` →<br>`{ start: '24:00:00', end: '01:00:00', delta: -82800000 }`
925906

926907
Here’s a skyviewcafe.com image for that extra-long day in the Marshall Islands, with two sunrises, two sunsets, and 24 hours, 6 minutes worth of daylight packed into a 47-hour day:
927908

@@ -1047,8 +1028,7 @@ As a string, `initialTime` can also include a trailing timezone or UTC offset, u
10471028

10481029
If the `timezone` argument is itself `null` or unspecified, this embedded timezone will become the timezone for the `DateTime` instance. If the `timezone` argument is also provided, the time will be parsed according to the first timezone, then it will be transformed to the second timezone.
10491030

1050-
`new DateTime('2022-06-01 14:30 America/Chicago', 'Europe/Paris', 'fr_FR').format('IMM ZZZ')` →<br>
1051-
`1 juin 2022 à 21:30:00 Europe/Paris`
1031+
`new DateTime('2022-06-01 14:30 America/Chicago', 'Europe/Paris', 'fr_FR').format('IMM ZZZ')` →<br>`1 juin 2022 à 21:30:00 Europe/Paris`
10521032

10531033
The following is an example of using the `gregorianChange` parameter to apply the change from the Julian to Gregorian calendar that was used by Great Britain, including what were the American colonies at the time:
10541034

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tubular/time",
3-
"version": "3.5.0",
3+
"version": "3.5.1",
44
"description": "Date/time, IANA timezones, leap seconds, TAI/UTC conversions, calendar with settable Julian/Gregorian switchover",
55
"main": "dist/cjs/index.js",
66
"module": "dist/fesm2015/index.js",

src/format-parse.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ describe('FormatParse', () => {
194194
expect(new DateTime('2021-08').format('MMMM YYYY', 'zh-tw')).to.equal('8月 2021');
195195
expect(new DateTime('2021-08').format('MMMM~YYYY~', 'zh-tw')).to.equal('8月2021年');
196196
expect(new DateTime('2021-08').format('MMMM~YYYY~', 'zh-cn')).to.equal('八月2021年');
197+
expect(new DateTime('2021-08').format('MMM~Y~', 'zh-cn')).to.equal('8月2021年');
198+
expect(new DateTime('2021-08').format('MMM~Y~', 'es')).to.equal('ago 2021');
197199
expect(new DateTime('2021-08').format('M~YYYY~', 'zh-cn')).to.equal('8月2021年');
198200
expect(new DateTime('2021-08').format('MM~YYYY~', 'zh-cn')).to.equal('08月2021年');
199201
expect(new DateTime('-2021-08').format('MMMM~y~n', 'ko')).to.equal('8월 2022년 BC');

src/format-parse.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const shortOpts = { Y: 'year', M: 'month', D: 'day', w: 'weekday', h: 'hour', m:
1515
ds: 'dateStyle', ts: 'timeStyle', e: 'era' };
1616
const shortOptValues = { f: 'full', m: 'medium', n: 'narrow', s: 'short', l: 'long', dd: '2-digit', d: 'numeric' };
1717
const styleOptValues = { F: 'full', L: 'long', M: 'medium', S: 'short' };
18-
const patternTokens = /({[A-Za-z0-9/_]+?!?}|V|v|R|r|I[FLMSx][FLMS]?|MMMM~?|MMM|MM~?|Mo|M~?|Qo|Q|DDDD|DDD|Do|DD~?|D~?|dddd|ddd|do|dd|d|E|e|ww|wo|w|WW|Wo|W|YYYYYY|yyyyyy|YYYY~?|yyyy|YY|yy|Y|y~?|N{1,5}|n|gggg|gg|GGGG|GG|A|a|HH|H|hh|h|kk|k|mm|m|ss|s|LTS|LT|LLLL|llll|LLL|lll|LL|ll|L|l|S+|ZZZ|zzz|ZZ|zz|Z|z|XT|xt|XX|xx|X|x)/g;
18+
const patternTokens = /({[A-Za-z0-9/_]+?!?}|V|v|R|r|I[FLMSx][FLMS]?|MMMM~?|MMM~?|MM~?|Mo|M~?|Qo|Q|DDDD|DDD|Do|DD~?|D~?|dddd|ddd|do|dd|d|E|e|ww|wo|w|WW|Wo|W|YYYYYY|yyyyyy|YYYY~?|yyyy|YY|yy|Y~?|y~?|N{1,5}|n|gggg|gg|GGGG|GG|A|a|HH|H|hh|h|kk|k|mm|m|ss|s|LTS|LT|LLLL|llll|LLL|lll|LL|ll|L|l|S+|ZZZ|zzz|ZZ|zz|Z|z|XT|xt|XX|xx|X|x)/g;
1919
const cachedLocales: Record<string, ILocale> = {};
2020

2121
let allNumeric: RegExp;
@@ -320,6 +320,7 @@ export function format(dt: DateTime, fmt: string, localeOverride?: string | stri
320320

321321
case 'MMM': // Short textual month
322322
result.push(locale.monthsShort[month - 1]);
323+
dateMark = dateMark && 2;
323324
break;
324325

325326
case 'MM': // 2-digit month

0 commit comments

Comments
 (0)