So if you've paid any attention to my previous posts you know that I'm working on a web app and recently started building out a mobile app that in its most basic form allows a captain to view booking, accept / decline, and manage their calendar. On the front end of the web app we went with FullCalendar wrapped in a Vue component and all of this data is being fed into the Laravel API. So let's break it all down real quick:
- FullCalendar is being powered by moment.js
NativeScript-ui-calendar which I use js Date object (I could bring in moment.js, but I want this app to be as lightweight as possible. full disclosure I don't officually know what nativescript uses under the hood to work with Date fields. To create an event I use
calendarModule.CalendarEventand that's all I know. I simply create an event and see that there is a startDate / endDate / title / color. Outside of that I am not sure I can do much else
- Carbon to manipulate time inside the API
So as you can see I'm dealing with time with multiple packages and obviously the time returned to the user needs to be consistent on whichever platform they are using. All of our captains have a stored time zone on each of their charters and to be consistent and I believe proper practice, all of our timestamps and any date / time related DB fields in UTC. This way it it's all stored with the same standard and can be converted as returned to whatever front end is calling for it.
One basic piece of functionality that is used both on FullCalendar and the Mobile calendar is allowing a captain to click on a date to "block it off" so that no one can schedule a booking for that date. So because America and when I'm writing this I will click on July 4 2021 of both FullCalendar and the nativescript calendar so you can see what I am given.
- FullCalendar -
- NativeScript -
Sun Jul 04 2021 00:00:00 GMT-0400 (EDT)As you can see here I can some extremely different data. But in the end I can normalize them both using Carbon. I won't go super in depth or any in depth by that means about it, but the FullCalendar is built inside a monolith from hell that uses the TALL stack and the mobile APP strictly gets data, so both calendars are getting data from separate routes. Both calendars however get Laravel JSON resources returned, both a tad different since FullCalendar has more options for events.
So before I go on I want to say that I have been doing things incorrectly and up until yesterday I was storing all data with a
00:00:00 timestamp and it bit me in the ass. I'm honestly not sure how I got this far with this particular items slipping through the cracks. I think it's cause on FullCalendar I was using all day events and didn't come across it until the mobile calendar converted timezones under the hood. I did however come up with a nice little bit of code that will properly convert all timestamps from one specific table to the timezone of the charter then to UTC then save, if in fact it was not already in proper form. Yea that sounds like a mouthful and sounds like a bit of a JR move but hey I screwed it up to begin with and came up with a reasonable solution. Some times as developers we just have to realize we've messed up, come up with a solution, and move on. I ran a bunch of local tests just to make sure this would not have any undesirable side effects and I feel 97% sure about it, and where I come from C's get degrees and I'm well above that shit so BAM!!!!!!!!
So Carbon has this cool createFromFormat method that accepts a format / time / timezone. These are the following standards that I'm using:
- Format -
- Time -
- TimeZone - this is gotten from the charter_id that is passed in
$charter->time_zone. I find the charter first
So now all data is normalized to the same Time / format. Also please note that this is solely being used for creating blocked dates. I would obviously not set the time of a trip/booking to 0,0 since it has one but since blocked dates are currently a full day affair this is perfect
For our final step for normalization is to convert the new timestamp into UTC timezone, which is as simple as
->tz('UTC'). Thank you Carbon for making that easy. You could also use the method
->setTimezone('UTC') which does the exact same thing, and I think you can also do
->setTimeZone('UTC'). So in my opinion this is why Carbon is the best. It seems to be the universal standard in laravel, where as in JS, people use Date, date.js, moment.js, and so on. I wish there was more of a "standard" but honestly use whatever works for you and call it a day.
So now I luckily have all of my data being stored properly in UTC in the DB. The only thing that remains is to convert it to the proper timezone on when data is returned to either FullCalendar or the App calendar. Since I'm using JSON resources and we'll call the resource
Range it's going to have (for dates) a start and an end. Also items that are used with both are Id (for obvious reasons) and title (which is just a string stating the events name). If you haven't used JSON resources from Laravel well they return an array of "data". Since everything is stored as UTC timezone, the only thing I need to do is convert that back to the local time zone of the charter and I can do this by:
'start' => $this->start->setTimezone($this->charter->time_zone), 'end' => $this->end->setTimezone($this->charter->time_zone),
The only thing that I am unsure of is if / how / when the underworking of the NativeScript calendar converts it to local time zone. The reason why is I noticed when I returned as a
00:00:00 timestamp it always showed up a day before because it was converted to the local time zone of the phone (emulator). Well when I send it back to the local timezone of the charter (presumably the phone as well), it showed up correct. So this may 100% come back to bite me in the future and I made a Trello ticket to keep it in the back of my mind but for now it works and I can move on to the next story.
The biggest takeaway that I've gotten so far from building out this app is that it has to be perfect, but why? Well I will just say it but our user base is dumb. Our admin staff gets calls on how to reset a password or they forgot theirs, when on the login screen it literally says
forgot password? and is a clickable link. That being said I'm 90% sure that when a captain downloads this app, they will never update it whatsoever, if they even download it. That means once this goes live that's it and little things like this really make me nervous as if something as simple as a timezone messes up their calendar but they cannot figure out how to reset a password, will they update the app, or even use it for that matter. But alas as a single programmer that is not my concern. I just cash a paycheck and slap the keyboard. Until next week..........