Skip to content

Commit

Permalink
Merge pull request #3 from remotehour/feature/fix-summer
Browse files Browse the repository at this point in the history
fix summer time bug, refactor
  • Loading branch information
acro5piano authored Oct 1, 2020
2 parents 15ece61 + 7132508 commit ad6aee3
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 22 deletions.
10 changes: 7 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ on: push
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10, 12]
tz: ["Z", "UTC", "Asia/Tokyo", "Pacific/Pago_Pago", "America/Los_Angeles"]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
node-version: ${{ matrix.node-version }}
- uses: actions/cache@master
with:
path: |
Expand All @@ -19,5 +23,5 @@ jobs:
yarn install
yarn tsc
yarn test
# env:
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
env:
TZ: ${{ matrix.tz }}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"ava": "^3.12.1",
"husky": "^4.3.0",
"lint-staged": "^10.4.0",
"mockdate": "^3.0.2",
"prettier": "^2.1.2",
"rollup": "^2.28.2",
"rollup-plugin-typescript2": "^0.27.3",
Expand All @@ -31,6 +32,6 @@
"rrule": "^2"
},
"dependencies": {
"dayjs": "^1.8.36"
"dayjs": "^1.9.1"
}
}
41 changes: 40 additions & 1 deletion src/CalendarEvent.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { CalendarEvent } from './CalendarEvent'
import { RRule } from 'rrule'
import test from 'ava'
import MockDate from 'mockdate'

const SUMMER = '2020-08-01T07:50:00Z'
const WINTER = '2020-02-01T07:50:00Z'

test.afterEach(() => {
MockDate.reset()
})

test('CalendarEvent - init with hour and minute, occurences', (t) => {
const event = new CalendarEvent({
Expand All @@ -24,10 +32,12 @@ test('CalendarEvent - init with hour and minute, occurences', (t) => {

t.is(event.toText(), '10:00 AM to 10:30 AM every month on the 3rd Friday')

MockDate.set(SUMMER)
t.deepEqual(
event.occurences({
between: [new Date('2020-09-01T00:00:00'), new Date('2020-12-31T00:00:00')],
between: [new Date('2020-05-01T00:00:00'), new Date('2020-12-31T00:00:00')],
}),
// FIXME: is it broken?
[
[new Date('2020-10-16T10:00:00Z'), new Date('2020-10-16T10:30:00Z')],
[new Date('2020-11-20T10:00:00Z'), new Date('2020-11-20T10:30:00Z')],
Expand Down Expand Up @@ -77,6 +87,8 @@ test('CalendarEvent - toText format & time zone', (t) => {
})

test('CalendarEvent - toText format prev date timezone', (t) => {
MockDate.set(SUMMER)

const event = new CalendarEvent({
start: {
dateTime: '2000-01-01T10:00:00Z',
Expand All @@ -101,3 +113,30 @@ test('CalendarEvent - toText format prev date timezone', (t) => {
'11:00 PM to the next day of 2:00 AM every day on Sunday, Thursday and every month on the 24th',
)
})

test('CalendarEvent - summer time', (t) => {
const event = new CalendarEvent({
start: {
hour: 10,
minute: 0,
tz: 'America/Los_Angeles',
},
end: {
hour: 10,
minute: 30,
tz: 'America/Los_Angeles',
},
recurrences: [
new RRule({
freq: RRule.DAILY,
}),
],
})

// We expect same result even if summer time
MockDate.set(WINTER)
t.is(event.toText({ tz: 'America/Los_Angeles' }), '10:00 AM to 10:30 AM every day')

MockDate.set(SUMMER)
t.is(event.toText({ tz: 'America/Los_Angeles' }), '10:00 AM to 10:30 AM every day')
})
35 changes: 22 additions & 13 deletions src/CalendarEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import timezone from 'dayjs/plugin/timezone'
dayjs.extend(utc)
dayjs.extend(timezone)

dayjs.tz.setDefault('UTC')

interface CalendarEventDef {
dateTime?: Date | string
hour?: number
Expand All @@ -32,27 +34,33 @@ interface OccurencesArgs {

const INITIAL_DATE = new Date(Date.UTC(2000, 0, 15, 0, 0, 0, 0))

function validateCalendarEventDef(e: CalendarEventDef, name: string) {
if ((e.hour === undefined || e.minute === undefined) && !e.dateTime) {
throw new Error(`invalid ${name} value. Either spcify dateTime or hour/minutes`)
}
}

function hasMinuteHour(e: CalendarEventDef): e is { hour: number; minute: number } {
return Number.isInteger(e.hour) && Number.isInteger(e.minute)
}

export class CalendarEvent {
private start: dayjs.Dayjs
private end: dayjs.Dayjs
private recurrences: RRuleSet

constructor({ start, end, recurrences }: CalendarEventArgs) {
if ((start.hour === undefined || start.minute === undefined) && !start.dateTime) {
throw new Error('invalid "start" value. Either spcify dateTime or hour/minutes')
}
if ((end.hour === undefined || end.minute === undefined) && !end.dateTime) {
throw new Error('invalid "end" value. Either spcify dateTime or hour/minutes')
}
validateCalendarEventDef(start, 'start')
validateCalendarEventDef(end, 'end')

this.start = dayjs.tz(start.dateTime || INITIAL_DATE, start.tz || 'UTC')
if (Number.isInteger(start.hour) && Number.isInteger(start.minute)) {
this.start = this.start.hour(start.hour!).minute(start.minute!)
if (hasMinuteHour(start)) {
this.start = this.start.hour(start.hour).minute(start.minute)
}

this.end = dayjs.tz(end.dateTime || INITIAL_DATE, end.tz || 'UTC')
if (Number.isInteger(end.hour) && Number.isInteger(end.minute)) {
this.end = this.end.hour(end.hour!).minute(end.minute!)
if (hasMinuteHour(end)) {
this.end = this.end.hour(end.hour).minute(end.minute)
}

this.recurrences = new RRuleSet()
Expand Down Expand Up @@ -89,12 +97,13 @@ export class CalendarEvent {
return this.recurrences.between(new Date(), until)
}

return this.recurrences.between(new Date(), dayjs().add(1, 'month').toDate())
return this.recurrences.between(new Date(), dayjs.utc().add(1, 'month').toDate())
}

toText({ tz = 'UTC', joinDatesWith = ' and ', timeFormat = 'h:mm A' }: ToTextArgs = {}) {
const start = dayjs.tz(this.start, tz)
const end = dayjs.tz(this.end, tz)
const start = this.start.tz(tz)
const end = this.end.tz(tz)

const occurencesText = this.recurrences
.clone()
.rrules()
Expand Down
13 changes: 9 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -604,10 +604,10 @@ date-time@^3.1.0:
dependencies:
time-zone "^1.0.0"

dayjs@^1.8.36:
version "1.8.36"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.36.tgz#be36e248467afabf8f5a86bae0de0cdceecced50"
integrity sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==
dayjs@^1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.9.1.tgz#201a755f7db5103ed6de63ba93a984141c754541"
integrity sha512-01NCTBg8cuMJG1OQc6PR7T66+AFYiPwgDvdJmvJBn29NGzIG+DIFxPLNjHzwz3cpFIvG+NcwIjP9hSaPVoOaDg==

debug@^4.1.1:
version "4.2.0"
Expand Down Expand Up @@ -1447,6 +1447,11 @@ minimist@^1.2.0:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==

mockdate@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.2.tgz#a5a7bb5820da617747af424d7a4dcb22c6c03d79"
integrity sha512-ldfYSUW1ocqSHGTK6rrODUiqAFPGAg0xaHqYJ5tvj1hQyFsjuHpuWgWFTZWwDVlzougN/s2/mhDr8r5nY5xDpA==

[email protected], ms@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
Expand Down

0 comments on commit ad6aee3

Please sign in to comment.