<div id="root">
@import "https://cdnjs.cloudflare.com/ajax/libs/react-datepicker/4.6.0/react-datepicker.css";
#root > div > button {
margin-bottom: 1rem;
}
View Compiled
import React from "https://cdn.skypack.dev/[email protected]";
import ReactDOM from "https://cdn.skypack.dev/[email protected]";
import DatePicker from "https://cdn.skypack.dev/[email protected]";
import * as JsJodaCore from "https://cdn.skypack.dev/@js-joda/[email protected]";
const { ZonedDateTime, Instant, ZoneId } = JsJodaCore;
/**
* You don't need this, but it helps to make the example more clear
*/
const FormattedErrorStack = (props) => {
const { error } = props;
if (!error) {
throw new Error(`expected the error prop to be truthy`);
}
return (
<div style={{ whiteSpace: "pre-line", color: "red" }}>
{error.stack ?? error.toString()}
</div>
);
};
const CUSTOM_COMPONENT_NAME = "ZonedDateTimePicker";
const ZonedDateTimePicker = (props) => {
const [error, setError] = React.useState(null);
const { zone, onChange, selected, ...otherProps } = props;
if (!!selected && !ZoneId.from(selected).equals(zone)) {
throw new Error(
`The provided date ("${selected}") was not in the expected ZoneId ("${zone}")`
);
}
const convertToZonedDateTime = (d) => {
try {
var instant = Instant.parse(d.toISOString());
var zdt = ZonedDateTime.ofInstant2(instant, zone);
onChange(zdt);
} catch (err) {
setError(err);
}
};
const prepareForDatePickerInput = (zdt) => {
return new Date(zdt.toInstant().toString());
};
if (error) {
console.error(error);
return (
<div>
<h1>Error within {CUSTOM_COMPONENT_NAME}</h1>
<div>
If you are seeing this then that means that {CUSTOM_COMPONENT_NAME} is
not doing the conversion properly and that means that this example
needs to be updated. Exact error message:
</div>
<br />
<FormattedErrorStack error={error} />
</div>
);
}
return (
<DatePicker
selected={selected ? prepareForDatePickerInput(selected) : null}
onChange={convertToZonedDateTime}
showTimeInput
preventOpenOnFocus={true}
timeInputLabel="Time:"
dateFormat="MM/dd/yyyy h:mm aa"
otherProps
/>
);
};
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { error: null };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { error };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.error(error, errorInfo);
}
render() {
if (!!this.state.error) {
// You can render any custom fallback UI
return (
<div>
<h1>Something went wrong.</h1>
<FormattedErrorStack error={this.state.error} />
</div>
);
}
return this.props.children;
}
}
const App = () => {
const [date, setDate] = React.useState(null);
const onChange = (updatedDate) => {
setDate(updatedDate);
};
return (
<ErrorBoundary>
<ZonedDateTimePicker
selected={date}
zone={ZoneId.of("-04:00")}
onChange={onChange}
/>
{!date ? (
<h2>Please select a date and time</h2>
) : (
<div>
<h2>Selected {CUSTOM_COMPONENT_NAME.replace("Picker", "")}</h2>
<div>String format for sending over HTTP: {date.toString()}</div>
</div>
)}
</ErrorBoundary>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.