Time/Date in JavaScript is so confusing. Seriously. Confusing
Read this if you're using Supabase PostgresQL + Mantine TimeInpu or another time input that uses a JavaScript Date, or if you just want to amuse yourself with my pain.
I ran into this really annoying issue and I came up with a really stupid solution (I hope someone tells me a better way!)
I'm currently building an app that requires me to ask a user for the open / closing time for a location like on Yelp. Of course, I thought this was going to be very straight forward.
- ask user for time open and time close : e.g. 8 am and 5 pm
- save the time to Postgres
- retrieve the saved time from Postgres and show the date or prefill the input
I pulled a little bit of hair out over this because I wanted to use Mantine UI's TimeInput with its use-form package. TimeInput uses a JavaScript Date as its value, which is all fine and dandy at first. But then I dug in and realized that the Date varies depending on where the user's device is. So 8AM input from California or New York is a completely different time that gets saved into Supabase Postgres database... (For Postgres, all timestamps are stored in UTC, so we call JavaScript Date's built-in .toISOString() to format it correctly for the database. 8AM PST -> 4pm UTC and 8 AM EST -> 1PM UTC)
It leads to some pretty weird edge cases when the time is saved in one timezone and viewed in another timezone.
I got super confused trying to figure out how to fix this and went through a bunch of rabbit holes down stack overflow.
- ask the user for timezone input and then set the date to that timezone (FAIL, JavaScript Dates are tracked in UTC internally and don't store a timezone on the Date Object, even if this worked the user's would only see the correct time if their device was in PST)
- Postgres timestamps are stored in UTC and JavaScript Dates are tracked internally as UTC, so why don't I just store everything as UTC and call it a day? (FAIL, when you reinitialize the UTC timestamp in Postgres on the client, the same problem above occurs, device must be in PST!)
Ultimately... the solution was so simple, albeit hacky. I pulled my hair out and just said: "I just want to save the hour and the date", so.... why don't I just do that?
I realized I don't care if the user's timezone is; I just care that they're selecting 8:00 pm (PST,EST, UTC, whatever, I don't care!). Instead of storing a timestamp in Postgres, I ended up creating an hours and minutes column.
const timeClosed = new Date('November 17, 2022 20:00:00');
await supabaseClient
.from("locations")
.update({
hours: timeClosed.getHours(),
minutes: timeClosed.getMinutes(),
})
In the database, we store these values, and when the data is fetched again, all we need to do is create a new Date() and set the hours and minutes and feed that into the Mantine UI TimeInput
function generateTime(hours: number, minutes: number) {
const baseDate = new Date();
baseDate.setHours(hours);
baseDate.setMinutes(minutes);
return baseDate;
}
// <TimeInput value={generateTime(database.open_hours, database_close_hours) />}
Ahh, relief, it works. I'm definitely not satisfied with the solution, but this is the best solution I have for now. ☺️
Thanks for reading!