Skip to content

Commit

Permalink
fix: Parse month string 'MMMM MMM (February, Feb)' in customParseForm…
Browse files Browse the repository at this point in the history
…at (#457)
  • Loading branch information
Kreozot authored and iamkun committed Feb 23, 2019
1 parent 44e9680 commit f343206
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 24 deletions.
40 changes: 20 additions & 20 deletions .babelrc → babel.config.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
"env": {
"test": {
"presets": [
"@babel/preset-env"
]
},
"build": {
"presets": [
[
"@babel/preset-env",
{
"modules": false,
"loose": true
}
]
]
}
}
}
module.exports = {
"env": {
"test": {
"presets": [
"@babel/preset-env"
]
},
"build": {
"presets": [
[
"@babel/preset-env",
{
"modules": false,
"loose": true
}
]
]
}
}
};
3 changes: 3 additions & 0 deletions docs/en/Plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ dayjs.extend(customParseFormat)

dayjs('05/02/69 1:02:03 PM -05:00', 'MM/DD/YY H:mm:ss A Z')
// Returns an instance containing '1969-05-02T18:02:03.000Z'

dayjs('2018 Enero 15', { format: 'YYYY MMMM DD', locale: es })
// Returns an instance containing '2018-01-15T00:00:00.000Z'
```

#### List of all available format tokens
Expand Down
17 changes: 17 additions & 0 deletions docs/es-es/Plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,23 @@ dayjs.extend(quarterOfYear)
dayjs('2010-04-01').quarter() // 2
```

### CustomParseFormat
- CustomParseFormat extends `dayjs()` constructor to support custom formats of input strings.

To escape characters, wrap them in square brackets (e.g. `[G]`). Punctuation symbols (-:/.()) do not need to be wrapped.

```javascript
import customParseFormat from 'dayjs/plugin/customParseFormat'

dayjs.extend(customParseFormat)

dayjs('05/02/69 1:02:03 PM -05:00', 'MM/DD/YY H:mm:ss A Z')
// Returns an instance containing '1969-05-02T18:02:03.000Z'

dayjs('2018 Enero 15', { format: 'YYYY MMMM DD', locale: es })
// Returns an instance containing '2018-01-15T00:00:00.000Z'
```

#### List of all available format tokens

| Format | Output | Description |
Expand Down
3 changes: 3 additions & 0 deletions docs/ja/Plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ dayjs.extend(customParseFormat)

dayjs('05/02/69 1:02:03 PM -05:00', 'MM/DD/YY H:mm:ss A Z')
// Returns an instance containing '1969-05-02T18:02:03.000Z'

dayjs('2018 5月 15', { format: 'YYYY MMMM DD', locale: ja })
// Returns an instance containing '2018-05-15T00:00:00.000Z'
```

#### List of all available format tokens
Expand Down
3 changes: 3 additions & 0 deletions docs/ko/Plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,9 @@ dayjs.extend(customParseFormat)

dayjs('05/02/69 1:02:03 PM -05:00', 'MM/DD/YY H:mm:ss A Z')
// Returns an instance containing '1969-05-02T18:02:03.000Z'

dayjs('2018 5월 15', { format: 'YYYY MMMM DD', locale: ko })
// Returns an instance containing '2018-05-15T00:00:00.000Z'
```

#### List of all available format tokens
Expand Down
3 changes: 3 additions & 0 deletions docs/pt-br/Plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ dayjs.extend(customParseFormat)

dayjs('05/02/69 1:02:03 PM -05:00', 'MM/DD/YY H:mm:ss A Z')
// Returns an instance containing '1969-05-02T18:02:03.000Z'

dayjs('2018 Fevereiro 15', { format: 'YYYY MMMM DD', locale: pt_br })
// Returns an instance containing '2018-02-15T00:00:00.000Z'
```

#### List of all available format tokens
Expand Down
3 changes: 3 additions & 0 deletions docs/zh-cn/Plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ dayjs.extend(customParseFormat)

dayjs('05/02/69 1:02:03 PM -05:00', 'MM/DD/YY H:mm:ss A Z')
// Returns an instance containing '1969-05-02T18:02:03.000Z'

dayjs('2018 五月 15', { format: 'YYYY MMMM DD', locale: zh_cn })
// Returns an instance containing '2018-05-15T00:00:00.000Z'
```

#### List of all available format tokens
Expand Down
6 changes: 3 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,16 @@ const parseDate = (date) => {

class Dayjs {
constructor(cfg) {
this.$L = this.$L || parseLocale(cfg.locale, null, true) || L
this.parse(cfg) // for plugin
}

parse(cfg) {
this.$d = parseDate(cfg.date)
this.init(cfg)
this.init()
}

init(cfg) {
init() {
const { $d } = this
this.$y = $d.getFullYear()
this.$M = $d.getMonth()
Expand All @@ -79,7 +80,6 @@ class Dayjs {
this.$m = $d.getMinutes()
this.$s = $d.getSeconds()
this.$ms = $d.getMilliseconds()
this.$L = this.$L || parseLocale(cfg.locale, null, true) || L
}

// eslint-disable-next-line class-methods-use-this
Expand Down
24 changes: 23 additions & 1 deletion src/plugin/customParseFormat/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const formattingTokens = /(\[[^[]*\])|([-:/.()\s]+)|(A|a|YYYY|YY?|MM?|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g
const formattingTokens = /(\[[^[]*\])|([-:/.()\s]+)|(A|a|YYYY|YY?|MM?M?M?|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g

const match1 = /\d/ // 0 - 9
const match2 = /\d\d/ // 00 - 99
Expand All @@ -9,6 +9,9 @@ const matchUpperCaseAMPM = /[AP]M/
const matchLowerCaseAMPM = /[ap]m/
const matchSigned = /[+-]?\d+/ // -inf - inf
const matchOffset = /[+-]\d\d:?\d\d/ // +00:00 -00:00 +0000 or -0000
const matchWord = /\d*[^\s\d]+/ // Word

let locale

function offsetFromString(string) {
const parts = string.match(/([+-]|\d\d)/g)
Expand Down Expand Up @@ -55,6 +58,24 @@ const expressions = {
DD: [match2, addInput('day')],
M: [match1to2, addInput('month')],
MM: [match2, addInput('month')],
MMM: [matchWord, function (input) {
const { months, monthsShort } = locale
const matchIndex = monthsShort
? monthsShort.findIndex(month => month === input)
: months.findIndex(month => month.substr(0, 3) === input)
if (matchIndex < 0) {
throw new Error()
}
this.month = matchIndex + 1
}],
MMMM: [matchWord, function (input) {
const { months } = locale
const matchIndex = months.indexOf(input)
if (matchIndex < 0) {
throw new Error()
}
this.month = matchIndex + 1
}],
Y: [matchSigned, addInput('year')],
YY: [match2, function (input) {
input = +input
Expand Down Expand Up @@ -144,6 +165,7 @@ export default (o, C) => {
proto.parse = function (cfg) {
const { date: input, format } = cfg
if (format) {
locale = this.$locale()
this.$d = parseFormattedInput(input, format)
this.init(cfg)
} else {
Expand Down
54 changes: 54 additions & 0 deletions test/plugin/customParseFormat.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import MockDate from 'mockdate'
import moment from 'moment'
import dayjs from '../../src'
import customParseFormat from '../../src/plugin/customParseFormat'
import uk from '../../src/locale/uk'

dayjs.extend(customParseFormat)

Expand Down Expand Up @@ -84,3 +85,56 @@ it('fails with an invalid format', () => {
expect(dayjs(input, format).format().toLowerCase())
.toBe(moment(input, format).format().toLowerCase())
})

it('parse month from string', () => {
const input = '2018 February 03'
const format = 'YYYY MMMM DD'
expect(dayjs(input, format).valueOf()).toBe(moment(input, format).valueOf())
})

it('parse month from short string', () => {
const input = '2018 Feb 03'
const format = 'YYYY MMM DD'
expect(dayjs(input, format).valueOf()).toBe(moment(input, format).valueOf())
})

it('parse month from string with locale in config', () => {
const input = '2018 лютий 03'
const format = 'YYYY MMMM DD'

expect(dayjs(input, { format, locale: uk }).valueOf()).toBe(moment(input, format, 'uk').valueOf())
})

it('parse month from short string with locale in config', () => {
const input = '2018 трав 03'
const format = 'YYYY MMM DD'
expect(dayjs(input, { format, locale: uk }).valueOf()).toBe(moment(input, format, 'uk').valueOf())
})

it('return Invalid Date when parse corrupt string', () => {
const input = '2018 Turnip 03'
const format = 'YYYY MMMM DD'
expect(dayjs(input, format).format()).toBe('Invalid Date')
})

it('return Invalid Date when parse corrupt short string', () => {
const input = '2018 Dog 03'
const format = 'YYYY MMM DD'
expect(dayjs(input, format).format()).toBe('Invalid Date')
})

it('correctly parse month from string after changing locale globally', () => {
const input = '2018 лютий 03'
const format = 'YYYY MMMM DD'

const dayjsLocale = dayjs().$locale()
const momentLocale = moment.locale()
try {
dayjs.locale(uk)
moment.locale('uk')
expect(dayjs(input, format).valueOf()).toBe(moment(input, format).valueOf())
} finally {
dayjs.locale(dayjsLocale)
moment.locale(momentLocale)
}
})

0 comments on commit f343206

Please sign in to comment.