Skip to content

Commit

Permalink
fix: changes date params to use JS Date
Browse files Browse the repository at this point in the history
This deprecates the usage of passing in ISO 8601 strings as dates. This
change fixes date-conversion and timezone issues #93, #104, and #107 by
providing the consumer with full control over the date and having
Datebook no longer mutate it.
  • Loading branch information
jshor committed Sep 26, 2020
1 parent 5860379 commit b63b562
Show file tree
Hide file tree
Showing 15 changed files with 139 additions and 88 deletions.
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
/></a> <a href="https://travis-ci.org/jshor/datebook"><img
src="https://img.shields.io/travis/jshor/datebook.svg?style=for-the-badge"
alt="Build status"
/></a> <a href="https://david-dm.org/jshor/datebook#info=dependencies"><img
src="https://img.shields.io/david/jshor/datebook.svg?style=for-the-badge"
alt="Dependency Status"
/></a> <a href="https://npmjs.com/package/datebook"><img
src="http://img.shields.io/npm/v/datebook.svg?style=for-the-badge"
alt="npm version"
Expand Down Expand Up @@ -57,9 +54,9 @@ import { ICalendar } from 'datebook'
const icalendar = new ICalendar({
title: 'Happy Hour',
location: 'The Bar, New York, NY',
description: 'Let\'s blow off some steam from our weekly deployments to enjoy a tall cold one!',
start: '2020-07-04T19:00:00',
end: '2020-07-04T23:30:00',
description: 'Let\'s blow off some steam with a tall cold one!',
start: new Date('2022-07-08T19:00:00'),
end: new Date('2022-07-08T23:30:00'),
recurrence: {
frequency: 'WEEKLY',
interval: 2
Expand Down
6 changes: 6 additions & 0 deletions docs/.vuepress/components/generators/Calendars.vue
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ export default {
recurrence: getFilteredRecurrence(this.config.recurrence)
}
config.start = new Date(config.start)
if (config.end) {
config.end = new Date(config.end)
}
if (this.allday) {
delete config.end
}
Expand Down
4 changes: 4 additions & 0 deletions docs/.vuepress/utils/getFilteredRecurrence.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
export default function getFilteredRecurrence (value) {
const recurrence = {...value}

if (recurrence.end) {
recurrence.end = new Date(recurrence.end)
}

if (recurrence.frequency === 'DAILY') {
// these fields are invalid for daily recurrences
delete recurrence.weekdays
Expand Down
44 changes: 22 additions & 22 deletions docs/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ import { ICalendar } from 'datebook'
const calendar = new ICalendar({
title: 'Happy Hour',
location: 'The Bar, New York, NY',
description: 'Let\'s blow off some steam from our weekly deployments to enjoy a tall cold one!',
start: '2020-07-04T19:00:00',
end: '2020-07-04T23:30:00',
description: 'Let\'s blow off some steam with a tall cold one!',
start: new Date('2022-07-08T19:00:00'),
end: new Date('2022-07-08T23:30:00'),
recurrence: {
frequency: 'WEEKLY',
interval: 2
Expand All @@ -43,18 +43,18 @@ BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:Let's blow off some steam from our weekly deployments to enjoy a tall cold one!
DTSTART:20190704T190000
DTEND:20190704T230000
DESCRIPTION:Let's blow off some steam with a tall cold one!
DTSTART:20220708T190000
DTEND:20220708T230000
LOCATION:The Bar, New York, NY
SUMMARY:Happy Hour
TRANSP:TRANSPARENT
RRULE:FREQ=WEEKLY;INTERVAL=2
RRULE:FREQ=DAILY;INTERVAL=1
END:VEVENT
END:VCALENDAR
UID:nmikriwwll
DTSTAMP:20200602
PRODID:localhost:8080
UID:19hq3v1lm15
DTSTAMP:20200916
PRODID:datebook.dev
```

## `YahooCalendar(options)`
Expand All @@ -73,9 +73,9 @@ import { YahooCalendar } from 'datebook'
const yahooCalendar = new YahooCalendar({
title: 'Happy Hour',
location: 'The Bar, New York, NY',
description: 'Let\'s blow off some steam from our weekly deployments to enjoy a tall cold one!',
start: '2020-07-04T19:00:00',
end: '2020-07-04T23:30:00',
description: 'Let\'s blow off some steam with a tall cold one!',
start: new Date('2022-07-08T19:00:00'),
end: new Date('2022-07-08T23:30:00'),
recurrence: {
frequency: 'WEEKLY',
interval: 2
Expand All @@ -88,7 +88,7 @@ yahooCalendar.render()
##### Result:

```
https://calendar.yahoo.com/?v=60&title=Happy%20Hour&st=20190704T190000&desc=Let%27s%20blow%20off%20some%20steam%20from%20our%20weekly%20deployments%20to%20enjoy%20a%20tall%20cold%20one!&in_loc=The%20Bar%2C%20New%20York%2C%20NY&RPAT=02Wk&REND=20190610T123112&dur=0200
https://calendar.yahoo.com/?v=60&title=Happy%20Hour&desc=Let's%20blow%20off%20some%20steam%20with%20a%20tall%20cold%20one!&in_loc=The%20Bar%2C%20New%20York%2C%20NY&st=20220708T190000&dur=0400&RPAT=01Wk&REND=20220708
```

This will open a modal in Yahoo! Calendar similar to the following:
Expand All @@ -111,9 +111,9 @@ import { GoogleCalendar } from 'datebook'
const googleCalendar = new GoogleCalendar({
title: 'Happy Hour',
location: 'The Bar, New York, NY',
description: 'Let\'s blow off some steam from our weekly deployments to enjoy a tall cold one!',
start: '2020-07-04T19:00:00',
end: '2020-07-04T23:30:00',
description: 'Let\'s blow off some steam with a tall cold one!',
start: new Date('2022-07-08T19:00:00'),
end: new Date('2022-07-08T23:30:00'),
recurrence: {
frequency: 'WEEKLY',
interval: 2
Expand All @@ -126,7 +126,7 @@ googleCalendar.render()
##### Result:

```
https://calendar.google.com/calendar/render?action=TEMPLATE&text=Happy%20Hour&details=Let%27s%20blow%20off%20some%20steam%20from%20our%20weekly%20deployments%20to%20enjoy%20a%20tall%20cold%20one!&location=The%20Bar%2C%20New%20York%2C%20NY&dates=20190704T190000%2F20190704T210000&recur=RRULE%3AFREQ%3DWEEKLY%3BINTERVAL%3D2%3BUNTIL%3D20190610T123926
https://calendar.google.com/calendar/render?action=TEMPLATE&text=Happy%20Hour&details=Let's%20blow%20off%20some%20steam%20with%20a%20tall%20cold%20one!&location=The%20Bar%2C%20New%20York%2C%20NY&dates=20220708T190000%2F20220708T230000&recur=RRULE%3AFREQ%3DWEEKLY%3BINTERVAL%3D1
```

This will open a form in Gmail similar to the following:
Expand All @@ -149,9 +149,9 @@ import { OutlookCalendar } from 'datebook'
const outlookCalendar = new OutlookCalendar({
title: 'Happy Hour',
location: 'The Bar, New York, NY',
description: 'Let\'s blow off some steam from our weekly deployments to enjoy a tall cold one!',
start: '2020-07-04T19:00:00',
end: '2020-07-04T23:30:00',
description: 'Let\'s blow off some steam with a tall cold one!',
start: new Date('2022-07-08T19:00:00'),
end: new Date('2022-07-08T23:30:00'),
recurrence: {
frequency: 'WEEKLY',
interval: 2
Expand All @@ -164,7 +164,7 @@ outlookCalendar.render()
##### Result:

```
https://outlook.live.com/calendar/0/deeplink/compose?path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-07-04T19%3A00%3A00&enddt=2019-07-04T23%3A00%3A00&subject=Happy%20Hour&body=Let's%20blow%20off%20some%20steam%20from%20our%20weekly%20deployments%20to%20enjoy%20a%20tall%20cold%20one!&location=The%20Bar%2C%20New%20York%2C%20NY&allday=false
https://outlook.live.com/calendar/0/deeplink/compose?path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2022-07-08T19%3A00%3A00&enddt=2022-07-08T23%3A00%3A00&subject=Happy%20Hour&body=Let's%20blow%20off%20some%20steam%20with%20a%20tall%20cold%20one!&location=The%20Bar%2C%20New%20York%2C%20NY&allday=false
```

This will open a modal in Outlook Online calendar similar to the following:
Expand Down
25 changes: 17 additions & 8 deletions docs/docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,28 @@ A summary description of the event location. Line breaks are automatically strip

### start

* Type: `string`
* Type: [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date), or `string` (deprecated)
* Required: **yes**
* Valid value: any [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) value.
* Valid value: a valid `Date` reference, or any [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) value (deprecated).

The event start timestamp. See [date formats](date.md) for more information.

:::warning Note
Specifying dates as strings is deprecated and will be removed in version **5.0.0**.
:::

### end

* Type: `string`
* Type: [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date), or `string` (deprecated)
* Required: **yes**, if not an all-day event
* Valid value: any [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) value.
* Valid value: a valid `Date` reference, or any [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) value (deprecated).

The event end timestamp. For all-day events, this field should be omitted. See [date formats](date.md) for more information.

:::warning Deprecation Notice
Specifying dates as strings is deprecated and will be removed in version **5.0.0**.
:::

## Recurrence

The recurrence of an event is how often the event is supposed to occur. Some examples of this could be:
Expand All @@ -54,7 +62,7 @@ The recurrence of an event is how often the event is supposed to occur. Some exa

Recurrence is **optional**.

:::warning Note
:::warning Deprecation Notice
This feature is not supported in Outlook online calendars.
:::

Expand Down Expand Up @@ -94,14 +102,15 @@ If this parameter is specified in conjunction with [`end`](#recurrence-end), the

### recurrence.end

* Type: `string`
* Type: [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date), or `string` (deprecated)
* Required: no
* Valid value: any [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) value.
* Valid value: a valid `Date` reference, or any [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) value (deprecated).

The latest date that this event may occur on. See [time formats](date.md) for more information.

:::warning Important
If this parameter is specified in conjunction with [`end`](#recurrence-end), the recurrence will end either when `count` is completed, or when `end` occurs, whichever happens first.
* Specifying dates as strings is deprecated and will be removed in version **5.0.0**.
* If this parameter is specified in conjunction with [`end`](#recurrence-end), the recurrence will end either when `count` is completed, or when `end` occurs, whichever happens first.
:::

### recurrence.weekdays
Expand Down
10 changes: 9 additions & 1 deletion docs/docs/date.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
# Date formats

Dates must be formatted as [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString). Dates not formatted this way will result in `NaN` returned as start and/or end times.
Dates, including `options.start`, `options.end`, and `recurrence.end`, should be passed in as JavaScript [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) objects. This provides full control over the date, including the specification of timezones.

## Legacy date support (deprecated)

For backwards compatibility, you may still provide the date as a `string` formatted as [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString). Dates not formatted this way will result in `NaN` returned as start and/or end times.

From the [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString):

> [The] simplified extended ISO format (ISO 8601), is always 24 or 27 characters long (`YYYY-MM-DDTHH:mm:ss.sssZ` or `±YYYYYY-MM-DDTHH:mm:ss.sssZ`, respectively). The timezone is always zero UTC offset, as denoted by the suffix "Z."
:::warning Deprecation Notice
Specifying dates as strings is deprecated and will be removed in version **5.0.0**.
:::

## Valid date examples

* `2021-07-04T21:20:15:00.000Z`
Expand Down
22 changes: 12 additions & 10 deletions src/CalendarBase.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { FORMAT } from './constants'
import { parseDate } from './utils/time'
import { incrementDate, parseDate } from './utils/time'

/**
* Base calendar class. This class can be extended to add new calendar services.
Expand All @@ -12,13 +11,13 @@ class CalendarBase {
* @param {String} options.description - event description
* @param {String} options.title - event title
* @param {String} options.location - event location
* @param {String} options.start - event start time, in [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#Date_Time_String_Format) format
* @param {String} [options.end] - event end time, in [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#Date_Time_String_Format) format
* @param {Date | String} options.start - event start time, in [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#Date_Time_String_Format) format
* @param {Date | String} [options.end] - event end time, in [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#Date_Time_String_Format) format
* @param {Object} [options.recurrence]
* @param {String} [options.recurrence.frequency] - recurrence frequency (`DAILY`, `WEEKLY`, `MONTHLY`, `YEARLY`)
* @param {Number} [options.recurrence.interval] - time between recurrences
* @param {Number} [options.recurrence.count] - number of times event should repeat
* @param {String} [options.recurrence.end] - date when the last recurrence should occur
* @param {Date | String} [options.recurrence.end] - date when the last recurrence should occur
* @param {String} [options.recurrence.weekstart = 'SU'] - uppercase, first two letters of the day that the week starts on
* @param {String} [options.recurrence.weekdays] - comma-separated list of uppercase, first two letters of the days the event occurs on
* @param {String} [options.recurrence.monthdays] - comma-separated list of monthdays String of numbers
Expand Down Expand Up @@ -48,24 +47,27 @@ class CalendarBase {
*
* @private
* @param {Object} options
* @param {String} options.start - event start time
* @param {String} [options.end] - event end time
* @param {Date | String} options.start - event start time
* @param {Date | String} [options.end] - event end time
* @param {Boolean} [options.allday = false] - whether this is an all-day event
* @param {Recurrence} [options.recurrence] - event recurrence
*/
setTimestamps (options) {
this.allday = !options.end
this.start = parseDate(options.start)

if (this.allday) {
// if allday is specified, make the end date exactly 1 day from the start date
this.end = parseDate(options.start)
this.end.setDate(this.end.getDate() + 1)
this.end = incrementDate(this.start, 1)
} else {
this.end = parseDate(options.end)
}

this.start = parseDate(options.start)
this.recurrence = options.recurrence

if (this.recurrence && this.recurrence.end) {
this.recurrence.end = parseDate(this.recurrence.end)
}
}
}

Expand Down
Loading

0 comments on commit b63b562

Please sign in to comment.