Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove luxon #508

Merged
merged 6 commits into from
Jun 5, 2022
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
17 changes: 7 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ Alternatively, download manually:

* [rrule.min.js](https://jakubroztocil.github.io/rrule/dist/es5/rrule.min.js) (bundled, minified)
* [rrule.js](https://jakubroztocil.github.io/rrule/dist/es5/rrule.js) (bundled, not minified)
* [rrule-tz.min.js](https://jakubroztocil.github.io/rrule/dist/es5/rrule-tz.min.js) (with timezone support, bundled, minified)
* [rrule-tz.js](https://jakubroztocil.github.io/rrule/dist/es5/rrule-tz.js) (with timezone support, bundled, not minified)
Copy link
Contributor

Choose a reason for hiding this comment

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

If there are projects loading from these github.io urls, for example using a <script> tag in an html file, this change will break those projects. I recommend we make a copy of rrule.min.js and rrule.js to rrule-tz.min.js and rrule-tz.js and continue to place them under dist folder.
But on the other hand, I don't know can we push users of these 2 files to switch. If we do not want to keep provide these files forever, eventually we need to stop and whenever we stop, it will break some body, so why not break it now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I hope nobody is linking directly to these files in a production app! It would be a very bad idea, since they're not versioned and can change unpredictably. Thus, I think it's a good idea to discourage that use case. These files are for direct download only. I would support removing even these links, and encourage everyone to just use npm as the source of truth for the package, but I think that's out of scope for this PR.


```html
<script src="rrule/dist/es5/rrule.min.js"></script>
Expand Down Expand Up @@ -192,7 +190,7 @@ date.getUTCDate() // --> 1
date.getUTCHours() // --> 18
```

If you want to get the same times in true UTC, you may do so eg. using Luxon:
If you want to get the same times in true UTC, you may do so eg. using [Luxon](https://moment.github.io/luxon/#/):

```ts
rule.all().map(date =>
Expand All @@ -215,11 +213,11 @@ For more examples see

### Timezone Support

Optionally, it also supports use of the `TZID` parameter in the
[RFC](https://tools.ietf.org/html/rfc5545#section-3.2.19)
when the [Luxon](https://github.com/moment/luxon) library is provided. The
[specification](https://moment.github.io/luxon/docs/manual/zones.html#specifying-a-zone)
and [support matrix](https://moment.github.io/luxon/docs/manual/matrix.html) for Luxon apply.
Rrule also supports use of the `TZID` parameter in the
[RFC](https://tools.ietf.org/html/rfc5545#section-3.2.19) using the
[Intl API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl).
Support matrix for the Intl API applies. If you need to support additional environments,
please consider using a [polyfill](https://formatjs.io/docs/polyfills/).

Example with `TZID`:

Expand Down Expand Up @@ -336,8 +334,7 @@ iCalendar RFC. Only `freq` is required.
</tr>
<tr>
<td><code>tzid</code></td>
<td>If given, this must be a string <a href="https://moment.github.io/luxon/docs/manual/zones.html#specifying-a-zone">supported</a>
by Luxon, and the <a href="https://moment.github.io/luxon/">Luxon</a> library must be provided. See
<td>If given, this must be a IANA string recognized by the Intl API. See
discussion under <a href="#timezone-support">Timezone support</a>.
</td>
</tr>
Expand Down
4 changes: 0 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
"@types/assert": "^1.4.3",
"@types/chai": "^4.2.7",
"@types/jquery": "^3.3.29",
"@types/luxon": "^1.21.0",
"@types/mocha": "^5.2.5",
"@types/mockdate": "^2.0.0",
"@types/node": "^12.12.18",
Expand Down Expand Up @@ -80,9 +79,6 @@
"dist",
"README.md"
],
"optionalDependencies": {
"luxon": "^1.21.3"
},
"peerDependencies": {},
"dependencies": {
"tslib": "^1.10.0"
Expand Down
18 changes: 5 additions & 13 deletions src/datewithzone.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import dateutil from './dateutil'
import { DateTime } from 'luxon'

export class DateWithZone {
public date: Date
Expand Down Expand Up @@ -32,18 +31,11 @@ export class DateWithZone {
return this.date
}

try {
const datetime = DateTime
.fromJSDate(this.date)
const localTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
const dateInLocalTZ = new Date(this.date.toLocaleString(undefined, { timeZone: localTimeZone }))
const dateInTargetTZ = new Date(this.date.toLocaleString(undefined, { timeZone: this.tzid ?? 'UTC' }))
const tzOffset = dateInTargetTZ.getTime() - dateInLocalTZ.getTime()

const rezoned = datetime.setZone(this.tzid!, { keepLocalTime: true })

return rezoned.toJSDate()
} catch (e) {
if (e instanceof TypeError) {
console.error('Using TZID without Luxon available is unsupported. Returned times are in UTC, not the requested time zone')
}
return this.date
}
return new Date(this.date.getTime() - tzOffset)
}
}
27 changes: 4 additions & 23 deletions test/datewithzone.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { DateWithZone } from "../src/datewithzone";
import { expect } from "chai";
import { DateTime } from "luxon";
import { set as setMockDate, reset as resetMockDate } from 'mockdate'
import { expectedDate } from "./lib/utils";

Expand Down Expand Up @@ -34,33 +33,15 @@ describe('rezonedDate', () => {

it('returns the date in the correct zone when given', () => {
const targetZone = 'America/New_York'
const currentLocalDate = DateTime.local(2000, 2, 6, 1, 0, 0)
setMockDate(currentLocalDate.toJSDate())
const currentLocalDate = new Date(2000, 1, 6, 1, 0, 0)
setMockDate(currentLocalDate)

const d = DateTime.fromISO('20101005T110000').toJSDate()
const d = new Date(Date.parse('20101005T110000'))
const dt = new DateWithZone(d, targetZone)
expect(dt.rezonedDate()).to.deep.equal(
expectedDate(DateTime.fromISO('20101005T110000'), currentLocalDate, targetZone)
expectedDate(new Date(Date.parse('20101005T110000')), currentLocalDate, targetZone)
)

resetMockDate()
})

it('recovers from an error if Luxon is missing', () => {
const origfromJSDate = DateTime.fromJSDate
DateTime.fromJSDate = () => {
throw new TypeError()
}

const targetZone = 'America/New_York'
const currentLocalDate = DateTime.local(2000, 2, 6, 1, 0, 0)
setMockDate(currentLocalDate.toJSDate())

const d = DateTime.fromISO('20101005T110000').toJSDate()
const dt = new DateWithZone(d, targetZone)
expect(dt.rezonedDate()).to.deep.equal(d)

DateTime.fromJSDate = origfromJSDate
resetMockDate()
})
})
21 changes: 9 additions & 12 deletions test/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { expect } from 'chai'
import { ExclusiveTestFunction, TestFunction } from 'mocha'
import { RRule, RRuleSet } from '../../src'
import { DateTime } from 'luxon';

const assertDatesEqual = function (actual: Date | Date[], expected: Date | Date[], msg?: string) {
msg = msg ? ' [' + msg + '] ' : ''
Expand Down Expand Up @@ -195,15 +194,13 @@ testRecurring.skip = function () {
it.skip.apply(it, arguments)
}

export function expectedDate(startDate: DateTime, currentLocalDate: DateTime, targetZone: string): Date {
const targetOffset = startDate.setZone(targetZone).offset
const { zoneName: systemZone } = currentLocalDate
const {
offset: systemOffset,
} = startDate.setZone(systemZone)

const netOffset = targetOffset - systemOffset
const hours = -((netOffset / 60) % 24)
const minutes = -(netOffset % 60)
return startDate.plus({ hours, minutes }).toJSDate()
export function expectedDate(startDate: Date, currentLocalDate: Date, targetZone: string): Date {
// get the tzoffset between the client tz and the target tz
const localTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
const dateInLocalTZ = new Date(startDate.toLocaleString(undefined, { timeZone: localTimeZone }))
const dateInTargetTZ = new Date(startDate.toLocaleString(undefined, { timeZone: targetZone }))
const tzOffset = dateInTargetTZ.getTime() - dateInLocalTZ.getTime()

return new Date(startDate.getTime() - tzOffset)
// return new Date(new Date(startDate.getTime() + tzOffset).toLocaleDateString(undefined, { timeZone: localTimeZone }))
}
5 changes: 2 additions & 3 deletions test/nlp.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { expect } from 'chai'
import { DateTime } from 'luxon'
import RRule from '../src';
import { optionsToString } from '../src/optionstostring';
import {DateFormatter} from '../src/nlp/totext'
Expand Down Expand Up @@ -94,7 +93,7 @@ describe('NLP', () => {
it('by default formats \'until\' correctly', () => {
const rrule = new RRule({
freq: RRule.WEEKLY,
until: DateTime.utc(2012, 11, 10).toJSDate()
until: new Date(Date.UTC(2012, 10, 10))
})

expect(rrule.toText()).to.equal('every week until November 10, 2012')
Expand All @@ -103,7 +102,7 @@ describe('NLP', () => {
it('formats \'until\' as desired if asked', () => {
const rrule = new RRule({
freq: RRule.WEEKLY,
until: DateTime.utc(2012, 11, 10).toJSDate()
until: new Date(Date.UTC(2012, 10, 10))
})

const dateFormatter: DateFormatter = (year, month, day) => `${day}. ${month}, ${year}`
Expand Down
28 changes: 13 additions & 15 deletions test/rrule.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { parse, datetime, testRecurring, expectedDate } from './lib/utils'
import { expect } from 'chai'
import { RRule, rrulestr, Frequency } from '../src/index'
import { DateTime } from 'luxon'
import { set as setMockDate, reset as resetMockDate } from 'mockdate'
import { optionsToString } from '../src/optionstostring';

describe('RRule', function () {
// Enable additional toString() / fromString() tests
Expand Down Expand Up @@ -3482,7 +3480,7 @@ describe('RRule', function () {
)

it('testAfterBefore', function () {
'YEARLY,MONTHLY,DAILY,HOURLY,MINUTELY,SECONDLY'.split(',').forEach(function (freqStr: keyof typeof Frequency) {
(['YEARLY','MONTHLY','DAILY','HOURLY','MINUTELY','SECONDLY'] as const).forEach(function (freqStr: keyof typeof Frequency) {
const date = new Date(1356991200001)
const rr = new RRule({
freq: RRule[freqStr],
Expand Down Expand Up @@ -3649,14 +3647,14 @@ describe('RRule', function () {
])
})

describe('time zones', () => {
describe('time zones, when recurrence is in dst', () => {
const targetZone = 'America/Los_Angeles'
const startDate = DateTime.utc(2013, 8, 6, 11, 0, 0)
const dtstart = startDate.toJSDate()
const startDate = new Date(Date.UTC(2013, 7, 6, 11, 0, 0))
const dtstart = startDate

it('generates correct recurrences when recurrence is in dst and current time is standard time', () => {
const currentLocalDate = DateTime.local(2013, 2, 6, 11, 0, 0)
setMockDate(currentLocalDate.toJSDate())
it('generates correct recurrences when current time is standard time', () => {
const currentLocalDate = new Date(2013, 1, 6, 11, 0, 0)
setMockDate(currentLocalDate)

const rule = new RRule({
dtstart,
Expand All @@ -3674,9 +3672,9 @@ describe('RRule', function () {
resetMockDate()
})

it('generates correct recurrences when recurrence is in dst and current time is dst', () => {
const currentLocalDate = DateTime.local(2013, 8, 6, 11, 0, 0)
setMockDate(currentLocalDate.toJSDate())
it('generates correct recurrences when current time is dst', () => {
const currentLocalDate = new Date(2013, 7, 6, 11, 0, 0)
setMockDate(currentLocalDate)

const rule = new RRule({
dtstart,
Expand All @@ -3694,9 +3692,9 @@ describe('RRule', function () {
resetMockDate()
})

it('generates correct recurrences when recurrence is in dst and current time is standard time', () => {
const currentLocalDate = DateTime.local(2013, 2, 6, 11, 0, 0)
setMockDate(currentLocalDate.toJSDate())
it('generates correct recurrences using after and current time is standard time', () => {
const currentLocalDate = new Date(2013, 1, 6, 11, 0, 0)
setMockDate(currentLocalDate)

const rule = new RRule({
dtstart,
Expand Down
Loading