Skip to content

Commit d68db5b

Browse files
committed
Switch to Luxon for date handling
1 parent b71c2a8 commit d68db5b

File tree

8 files changed

+44
-80
lines changed

8 files changed

+44
-80
lines changed

package-lock.json

Lines changed: 15 additions & 51 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"body-parser": "^2.2.0",
99
"ejs": "^3.1.10",
1010
"express": "^5.1.0",
11+
"luxon": "^3.6.1",
1112
"normalize.css": "^8.0.1"
1213
},
1314
"devDependencies": {
@@ -32,8 +33,6 @@
3233
"husky": "^9.1.7",
3334
"jest": "^30.0.0",
3435
"jest-environment-jsdom": "^30.0.0",
35-
"moment": "^2.30.1",
36-
"moment-locales-webpack-plugin": "^1.2.0",
3736
"postcss": "^8.5.6",
3837
"postcss-loader": "^8.1.1",
3938
"react": "^16.14.0",

src/components/__tests__/search-bar.test.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { render, screen, fireEvent } from '@testing-library/react';
44
import SearchBar from '../search-bar/search-bar';
5-
import moment from 'moment';
5+
import { DateTime } from 'luxon';
66

77
describe('search-bar', () => {
88
// Need to use a fake timer because the _urlSearch function is debounced.
@@ -53,7 +53,7 @@ describe('search-bar', () => {
5353

5454
expect(onSearch).toHaveBeenCalledWith({
5555
url: null,
56-
startDate: expect.any(moment),
56+
startDate: expect.any(DateTime),
5757
endDate: null
5858
});
5959
});
@@ -68,7 +68,7 @@ describe('search-bar', () => {
6868
expect(onSearch).toHaveBeenCalledWith({
6969
url: null,
7070
startDate: null,
71-
endDate: expect.any(moment)
71+
endDate: expect.any(DateTime)
7272
});
7373
});
7474
});

src/components/search-bar/search-bar.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { Component } from 'react';
22
import styles from './search-bar.css';
33
import SearchDatePicker from '../search-date-picker/search-date-picker';
44

5+
/** @typedef {import("luxon").DateTime} DateTime */
6+
57
/**
68
* @typedef SearchBarProps
79
* @property {(SearchBarQuery) => void} onSearch
@@ -87,8 +89,8 @@ export default class SearchBar extends Component {
8789
/**
8890
* Updates query state with date range information.
8991
*
90-
* @param {Date} startDate moment object from date picker
91-
* @param {Date} endDate moment object from date picker
92+
* @param {DateTime} startDate Luxon DateTime object from date picker
93+
* @param {DateTime} endDate Luxon DateTime object from date picker
9294
*/
9395
_dateSearch ({ startDate, endDate }) {
9496
this.setState({ startDate, endDate });

src/components/search-date-picker/search-date-picker.jsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { Component } from 'react';
2-
import moment from 'moment';
2+
import { DateTime } from 'luxon';
33
import styles from './search-date-picker.css';
44

55
/**
66
* @typedef SearchDatePickerProps
7-
* @property {({startDate: moment.Moment, endDate: Moment.moment}) => void} onDateSearch
8-
* @property {Date|moment.Moment} startDate
9-
* @property {Date|moment.Moment} endDate
7+
* @property {({startDate: DateTime, endDate: DateTime}) => void} onDateSearch
8+
* @property {DateTime} startDate
9+
* @property {DateTime} endDate
1010
*/
1111

1212
/**
@@ -26,7 +26,7 @@ export default class SearchDatePicker extends Component {
2626
}
2727

2828
handleChange (event) {
29-
const value = event.target.value ? moment(event.target.value) : null;
29+
const value = event.target.value ? DateTime.fromISO(event.target.value) : null;
3030
this.props.onDateSearch({
3131
startDate: this.props.startDate,
3232
endDate: this.props.endDate,
@@ -42,19 +42,19 @@ export default class SearchDatePicker extends Component {
4242
<input
4343
type="date"
4444
name="startDate"
45-
value={this.props.startDate?.toISOString()?.slice(0, 10) ?? ''}
45+
value={this.props.startDate?.toISODate() ?? ''}
4646
onChange={this.handleChange}
47-
max={(new Date()).toISOString().slice(0, 10)}
47+
max={DateTime.now().toISODate()}
4848
/>
4949
</label>
5050
<label className={styles.searchDateField}>
5151
To date:
5252
<input
5353
type="date"
5454
name="endDate"
55-
value={this.props.endDate?.toISOString()?.slice(0, 10) ?? ''}
55+
value={this.props.endDate?.toISODate() ?? ''}
5656
onChange={this.handleChange}
57-
max={moment().add(1, 'days').toISOString().slice(0, 10)}
57+
max={DateTime.now().plus({ days: 1 }).toISODate()}
5858
/>
5959
</label>
6060
</>

src/scripts/__tests__/db-helpers.test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/* eslint-env jest */
22
import { formatDateRange } from '../db-helpers';
3-
import moment from 'moment';
3+
import { DateTime } from 'luxon';
44

55
describe('db-helpers', () => {
6-
test('formatDateRange returns correct query parameter value when moment object is passed in', () => {
7-
const startDate = moment('26 Oct 2019 21:00:00 PST');
8-
const endDate = moment('27 Oct 2019 21:00:00 PST');
6+
test('formatDateRange returns correct query parameter value when DateTime object is passed in', () => {
7+
const startDate = DateTime.fromISO('2019-10-26T21:00:00-08:00');
8+
const endDate = DateTime.fromISO('2019-10-27T21:00:00-08:00');
99
const dateRangeString = formatDateRange({ startDate, endDate });
1010

1111
expect(dateRangeString).toBe('2019-10-27T05:00:00.000Z..2019-10-28T05:00:00.000Z');

src/scripts/db-helpers.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1+
/** @typedef {import("luxon").DateTime} DateTime */
2+
13
/**
2-
* Takes a date (either a moment or Date object) and returns an ISO date string in UTC time.
3-
* If there is no date, return an empty string.
4+
* Takes a date (either a Luxon DateTime or Date object) and returns an ISO date
5+
* string in UTC time. If there is no date, return an empty string.
46
* Throws a TypeError if an invalid value is passed in.
57
* @private
6-
* @param {String|Date|Moment} date
8+
* @param {String|Date|DateTime} date
79
*
810
* @returns {String}
911
*/
1012
function _formatDate (date) {
1113
if (!date) return '';
14+
else if (date.toISO) return date.toUTC().toISO();
1215
else if (date.toISOString) return date.toISOString();
13-
else throw new TypeError(`formatDate only takes Moment or Date instances, not ${date.constructor.name}s`);
16+
else throw new TypeError(`formatDate only takes Date or luxon.DateTime instances, not ${date.constructor.name}s`);
1417
}
1518

1619
/**

webpack.config.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const autoprefixer = require('autoprefixer');
22
const CompressionPlugin = require('compression-webpack-plugin');
3-
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
43
const path = require('path');
54
const zopfli = require('@gfx/zopfli');
65

@@ -141,10 +140,7 @@ module.exports = {
141140
}
142141
],
143142
},
144-
plugins: [
145-
// Strip locales from Moment.js (we only use English)
146-
new MomentLocalesPlugin()
147-
],
143+
plugins: [],
148144
};
149145

150146
// Production-specific additions

0 commit comments

Comments
 (0)