Skip to content
This repository was archived by the owner on Sep 27, 2023. It is now read-only.
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
12 changes: 12 additions & 0 deletions src/fiscal-periods/date-param.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DateParam } from '~/fiscal-periods/date-param'
import { ParseError } from '~/fiscal-periods/error'

test('toString', () => {
expect(new DateParam('latest').toString()).toEqual('latest')
Expand All @@ -16,3 +17,14 @@ test('isLatest', () => {
expect(new DateParam('latest').isLatest()).toBeTruthy()
expect(new DateParam(new Date('2020-09-06')).isLatest()).toBeFalsy()
})

test('parse', () => {
expect(DateParam.parse('2020-09-06')).toEqual(
new DateParam(new Date(2020, 9, 6))
)
expect(DateParam.parse('latest')).toEqual(new DateParam('latest'))
expect(DateParam.parse('Latest')).toEqual(new DateParam('latest'))
expect(() => DateParam.parse('foo')).toThrow(ParseError)
expect(() => DateParam.parse('2020-9-6')).toThrow(ParseError)
expect(() => DateParam.parse('2020/09/06')).toThrow(ParseError)
})
19 changes: 19 additions & 0 deletions src/fiscal-periods/date-param.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ParseError } from '~/fiscal-periods/error'

export class DateParam {
constructor(public date: Date | 'latest') {}

Expand All @@ -20,4 +22,21 @@ export class DateParam {
public isLatest(): boolean {
return this.date === 'latest'
}

static parse(str: string): DateParam {
str = str.toLowerCase()
if (str == 'latest') {
return new DateParam(str)
}
Comment on lines +27 to +30
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

なるほど ま、設定値に切り出すほどでもないか


const matches = str.match(/^(\d{4})-(\d{2})-(\d{2})$/)
if (matches == undefined) {
throw new ParseError(`Invalid date format: ${str}`)
}
Comment on lines +32 to +35
Copy link
Copy Markdown
Contributor

@shoe116 shoe116 Nov 7, 2021

Choose a reason for hiding this comment

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

あー これ自前でvalidation する?直接 Date.parse して例外処理っていうのもありだと思うけど。

実行環境毎に Date.parse の挙動が違うとかそういうのを想定してる?

Copy link
Copy Markdown
Contributor Author

@akiomik akiomik Nov 8, 2021

Choose a reason for hiding this comment

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

jsの new Date(str) はいろんなフォーマットでパースできてしまうので、将来的に別のフォーマットを追加した際に挙動が変わってしまう懸念があり、なるべくフォーマットは固定化した方がいいと思っています
(例えば年次ごとの値を取得するエンドポイントが追加されたとき、 BCODE(ticker, 2020, propName) みたいな関数呼び出しの口になると、 new Date('2020') のパースと = 2020-01-01 と衝突してしまう)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

なるほど


const year = parseInt(matches[1], 10)
const month = parseInt(matches[2], 10)
const day = parseInt(matches[3], 10)
return new DateParam(new Date(year, month, day))
}
}
9 changes: 9 additions & 0 deletions src/fiscal-periods/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,12 @@ export class InvalidLYLQError implements Error {
this.message = message
}
}

export class ParseError implements Error {
public name = 'ParseError'
public message: string

constructor(message = '') {
this.message = message
}
}
17 changes: 17 additions & 0 deletions src/fiscal-periods/period-parser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { DateParam } from '~/fiscal-periods/date-param'
import { ParseError } from '~/fiscal-periods/error'
import { PeriodParser } from '~/fiscal-periods/period-parser'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'

test('parse', () => {
expect(PeriodParser.parse('2020Q3')).toEqual(new YearQuarterParam(2020, 3))
expect(PeriodParser.parse('LYLQ')).toEqual(new YearQuarterParam('LY', 'LQ'))
expect(PeriodParser.parse('2020-09-06')).toEqual(
new DateParam(new Date(2020, 9, 6))
)
expect(() => PeriodParser.parse('foo')).toThrow(ParseError)
expect(() => PeriodParser.parse('2020LQ')).toThrow(ParseError)
expect(() => PeriodParser.parse('LYQ3')).toThrow(ParseError)
expect(() => PeriodParser.parse('2020/09/06')).toThrow(ParseError)
expect(() => PeriodParser.parse('latest')).toThrow(ParseError)
})
30 changes: 30 additions & 0 deletions src/fiscal-periods/period-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { DateParam } from '~/fiscal-periods/date-param'
import { ParseError } from '~/fiscal-periods/error'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'

export class PeriodParser {
constructor() {
// noop
}

static parse(str: string): DateParam | YearQuarterParam {
str = str.toUpperCase()

try {
return YearQuarterParam.parse(str)
} catch {
// noop
}

try {
const date = DateParam.parse(str)
if (!date.isLatest()) {
return date
}
} catch {
// noop
}

throw new ParseError(`Invalid period format: ${str}`)
}
}
22 changes: 21 additions & 1 deletion src/fiscal-periods/year-quarter-param.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
InvalidLYLQError,
InvalidYearError,
InvalidQuarterError
InvalidQuarterError,
ParseError
} from '~/fiscal-periods/error'
import { YearQuarter } from '~/fiscal-periods/year-quarter'
import { YearQuarterParam } from '~/fiscal-periods/year-quarter-param'
Expand Down Expand Up @@ -50,3 +51,22 @@ test('fromYearQuarter', () => {
new YearQuarterParam(2018, 1)
)
})

test('parse', () => {
expect(YearQuarterParam.parse('2020Q3')).toEqual(
new YearQuarterParam(2020, 3)
)
expect(YearQuarterParam.parse('2020q3')).toEqual(
new YearQuarterParam(2020, 3)
)
expect(YearQuarterParam.parse('LYLQ')).toEqual(
new YearQuarterParam('LY', 'LQ')
)
expect(YearQuarterParam.parse('lylq')).toEqual(
new YearQuarterParam('LY', 'LQ')
)
expect(() => YearQuarterParam.parse('20Q3')).toThrow(ParseError)
expect(() => YearQuarterParam.parse('LYQ3')).toThrow(InvalidLYLQError)
expect(() => YearQuarterParam.parse('2020LQ')).toThrow(InvalidLYLQError)
expect(() => YearQuarterParam.parse('foo')).toThrow(ParseError)
})
17 changes: 16 additions & 1 deletion src/fiscal-periods/year-quarter-param.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
InvalidLYLQError,
InvalidYearError,
InvalidQuarterError
InvalidQuarterError,
ParseError
} from '~/fiscal-periods/error'
import { YearQuarter } from '~/fiscal-periods/year-quarter'

Expand Down Expand Up @@ -44,6 +45,20 @@ export class YearQuarterParam {
return this.quarter === 'LQ'
}

// XXX: LYLQの同時指定や-1などの相対値指定をどうするか確認する
static parse(str: string): YearQuarterParam {
str = str.toUpperCase()
const matches = str.match(/^(\d{4}|LY)(Q\d|LQ)$/)
if (matches == undefined) {
throw new ParseError(`Invalid year-quarter format: ${str}`)
}

const year = matches[1] === 'LY' ? 'LY' : parseInt(matches[1], 10)
const quarter =
matches[2] === 'LQ' ? 'LQ' : parseInt(matches[2].substring(1), 10)
return new YearQuarterParam(year, quarter)
}

static fromYearQuarter(period: YearQuarter): YearQuarterParam {
return new YearQuarterParam(period.year, period.quarter)
}
Expand Down