Generating rrules based on certain timezones - javascript

Let's say I have a user of my application set a recurring event. His timezone is America/Denver, so I store that along with an rrule that determines when the recurrences happen.
This works assuming that both my server and all of my users are in the same time zone. However, let's say I have other users, in America/Pheonix and maybe America/New_York who wants to get the occurances of this event the user has defined. I need to be able to create the events using the America/Denver time, but then return them to the user in UTC. Conversely, I also need to calculate recurring events that users in America/New_York defined and return those as UTC to the user.
Is there a library that exists that I can give it a timezone and an rrule and have it generate the recurring events based on that timezone's rules (like respecting DST)? Or maybe a third party API?
EDIT: Here is some clarity to my problem.
Let's say I have a recurring event that occurs every Friday at 9am. If I set this event in Colorado, the times that this event occurs are going to be slightly different than times in Arizona, which doesn't have DST for the 5 months of the year that Colorado does. So in my database, I need to store the time zone, and I need some way to generate the events based on that time zone's rules. This is the part I am stuck on, finding a way to generate the events based on the time zone's rules.

I need some way to generate the events based on that time zone's rules
No, you don't. The "time zone's rules" are irrelevant to the generation of occurrences. An event at "every Friday at 9am" is going to be at 9am all year round, whether DST is active or not. In other words, you can (and should) completely ignore DST for the rrule part.
The only thing you need to do is keep the original time zone along with each occurrence - a date and a time is not enough - then simply convert the date/time to another time zone on the fly, when you need to display it to a different user.
I have used Moment.js and Moment Timezone to work with dates before, but you probably have other options out there.

Related

Future bookings maintain business timezone for displaying data when in other timezone

I am setting up a webapp for a business which takes future bookings which can also be recurring. At this moment, only the business can make the bookings.
Business rules:
The app must save a timezone against the user based on the business address provided at account registration. All events will be taking place at the business address. UPDATE: following comments, this rule will be changed to: Timezone will be recommended to the user user using a geocoding service (in the instance that a match is found), but user must confirm their timezone.
When logging in from another timezone, the webapp app booking system should still appear to the user to be set to the business timezone. (Potential scenario for this is the user is at a meeting abroad, but still wants to check up on their bookings). This should mean that they can still use the system as before eg. by adding new bookings. However, I believe this would mean the system has to ignore the user's local timezone, and apply the business timezone to any booking events.
I have the booking system working for a user that is within the same timezone. But when they change timezones the future bookings calendar breaks.
My app is nodeJS with postgresql. What I am confused about is what I should be persisting with regards to datetimes, and what relevant conversions to perform.
I think it would be prudent to save the client locale datetime always (even if not used as requirements may change), and also the UTC time. But I think I will have to also construct a date (in javascript) that takes the datetime selected and applies the business timezone to this (using eg. moment.tz.setDefault("America/New_York")?). I am unsure what to do about receiving this date on the client when viewing the scheduling information. How do I ensure that it displays with the business timezone?
You should always store the time zone that is relevant to the event. Since you said "All events will be taking place at the business address", then the time zone of the business is relevant.
If these are physical in-person events, then the user's current local time zone isn't relevant at all. For example, I would expect that if I made a dentist appointment in Los Angeles, that I would specify the time in Los Angeles even if I was making the appointment from New York.
However, if the events are virtual online events, then you may also want to add some logic in the UX to show both the time in the target time zone and the equivalent local time. For example, if I'm scheduling a video call next week with a person in Los Angeles, and I happen to be in New York today, you have no idea whether I will still be in New York at the time of the call or if I'll have travelled to Los Angeles by then. You should allow me to choose which time zone I'm creating the appointment in, and show both the time there and my equivalent local time.
The time zone itself should be stored as a varchar(14). IANA 2017c established a 14 character limit for individual segments of zone or link identifiers, removing the only link name that exceeded it, Canada/East-Saskatchewan. (If you have older data that includes that, replace it with America/Regina.)
For a single appointment, you should store the date and time of the appointment, in the time zone of the appointment. You should store this in a data type that holds the date and time without any time zone or offset. timestamp without time zone in postgres, datetime2 in MS Sql Server, etc.
You might think you should use a timestamp with timezone (or datetimeoffset type in SQL Server), but that would pin the appointment to the equivalent universal time, using the rules applicable at the time the appointment was scheduled. If those rules change before the appointment comes into effect, then the appointment will shift to a different local time. This is usually undesired. The point is to capture the intent of the user. In other words, if I say "8am on December 1st", then I mean that regardless of what my government does to my time zone between now and my appointment time.
You might also store the UTC time equivalent in a separate field, but you'd need to recompute it any time the server's time zone data was updated. (Such a field can be convenient to quickly query for upcoming events.)
For a recurring appointment, all the above still applies except that you'll need to store some form of recurrence rule. Some people like to store many fields for various components of the rule (such as one field for "daily", one field for "on Wednesdays", one field for the time of day, etc...). You can use the date and time types in your database if you like. Other people like to store a string with a chron expression. It really just depends on your needs.
It's especially important with recurring appointments to consider that the UTC equivalent for each occurrence will not necessarily be the same. Consider that many time zones alternate their UTC offsets based on whether daylight saving time is in effect. For example, if I'm creating a daily appointment in Los Angeles at 10 am, that would be 6 pm UTC during Pacific Standard Time, and 5 pm UTC during Pacific Daylight Time. Thus, you cannot just store the UTC time. Again, capturing the intent of the user is the most important part.

How do I get the result of javascript new Date().getTimezoneOffset() transferred to C# backend?

See the title: for the solution I'm working on, I need to get the current timezone offset (from the client, running javascript/jQuery) and use it in backend C# code.
The question is rather similar to the one asked here, but there are a few differences - the main one being that I am pretty sure that the time on the client computer won't be tampered with. So new Date().getTimezoneOffset() will do just fine.
I cannot read the value upon submitting a form since the user is not working in a form: after the user has logged in, among the items that are visible on the screen is a table with data entered by the user or by other users. This data contains UTC datetimes that have to be adjusted according to the client's timezone. C# code is responsible for retrieving and formatting the data - hence my question.
What would suffice, is storing the value somewhere so that C# can read it when necessary. But I don't think that can be done as well. What would be the approach here?
Thanks in advance!
Your suggested approach is flawed in that the current offset from the client's browser is only going to apply to the current date and time. In reality, time zone offsets change over time within a given time zone. You cannot just take a singular offset from one point in time and expect to use it to convert other dates and times to the same time zone. Instead, you need to use the string that identifies the time zone, not an offset from that zone.
As an example, consider the Eastern time zone in the United States. For part of the year, it uses UTC-5, and we call it Eastern Standard Time (EST). In another other part of the year, it uses UTC-4, and we call it Eastern Daylight Time (EDT). This time zone is identified by either the IANA time zone ID "America/New_York", or the Windows time zone ID "Eastern Standard Time" (which covers the entire zone, both EST and EDT despite its wording).
So, break this problem apart into a few steps:
In JavaScript, identify the users's IANA time zone (America/New_York):
If you are targeting modern web browsers, you can call this function:
Intl.DateTimeFormat().resolvedOptions().timeZone
If you need to support older web browsers, you can use jsTimeZoneDetect, or moment.tz.guess() from Moment-Timezone.
Send that string to your web server through whatever mechinsm you like (form post, XHR, fetch, etc.)
In your .NET code, receive that string and use it to reference the time zone and do the conversion. You have two options:
You can use Noda Time, passing the IANA time zone ID to DateTimeZoneProviders.Tzdb as shown in the example on the home page.
You can use .NET's built-in TimeZoneInfo object. If you're running .NET Core on non-Windows systems (Linux, OSX, etc.) you can just pass the IANA time zone ID to TimeZoneInfo.FindSystemTimeZoneById. If you are on Windows, you'll need to first convert it to a Windows time zone ID ("Eastern Standard Time"). You can use TZConvert.GetTimeZoneInfo from my TimeZoneConverter library.
Once you have either a DateTimeZone from Noda Time, or a TimeZoneInfo object, you can use the methods on it to convert UTC values to local time values for that time zone. Each of these will apply the correct offset for the point in time being converted.
I'll also say, many applications simply ask the user to choose their time zone from a dropdown list and save it in a user profile. As long as you're storing a time zone identifier string and not just a numeric offset, this approach is perfectly acceptable to replace steps 1 and 2 above.

Does DST affect the Date() object

I am building a small web application that has some time based aspects to it like displaying and hiding things based on what hour in the day it is. My friend told me that this will work until DST comes around and then I will have to change all of the hour checks I have in place. Is this true?
When creating a new Date() it will represent the user's current time regardless of circumstances. From MDN:
When no parameters are provided, the newly-created Date object represents the current date and time, specified in the local time zone, as of the time of instantiation.
I would strongly recommend not trying to handle DST yourself, because it becomes heinously complicated once you get into the weeds.

Managing timezone & DST issue for javascript application

I am trying to create a scheduling application. The front end\UI is developed using JavaScript. The back end is a ASP.NET Web Api application which uses MSSQL server as the database. From the UI, user will schedule a job which can run daily/weekly/monthly. Each job can run for maximum of 3 months. The job will run on the server side at the specified time.
Assume user come and selects a job which will run for a week (From 23-Nov to 29-Nov) at 10 AM local time. In this case, I will make seven entries in the database starting from 23 nov (One for each day). Each row will have Start time, Start Date and some status related columns.
I have following querstions:
How do I store time information (10 AM in this case)on SQL server?
Should I get the time using JavaScript on client machine and then convert the same to UTC?
Should I get the time using JavaScript and also save the user time zone information?
What happens when DST related changes take effect?
Will library like momemnt.js will help in this scenario?
I am thinking of saving user timezone information and the saving his local time on the server.
Warning - Scheduling properly is hard. There's a lot more to consider. Please read this and this. Most of your questions are addressed there (though from the perspective of other languages, the challenges are the same).
You might also take a look at Quartz.net, which is sufficient for many scenarios.
To answer your specific questions:
How do I store time information (10 AM in this case) on SQL server?
For the recurrence rule, store the local time of the event. SQL Server has a time type, which works well for storing the time of day. You will need other fields for tracking the time zone, the start date, days of the week, and other pattern information.
For the specific instance that is scheduled to run, you calculate the UTC datetime based on all the information in the recurrence rule. At minimum, you schedule the next occurrence, and recalculate after each run. In some cases, you may decide to project the next N occurrences, depending on what you need to show to the users. (You could also use a datetimeoffset for this purpose. See datetime vs datetimeoffset.)
Should I get the time using JavaScript on client machine and then convert the same to UTC?
Should I get the time using JavaScript and also save the user time zone information?
To answer both questions: For scheduling, you should not discard the original input, which will be in the local time zone of the event being scheduled. That may or may not match the time zone of the user. You will need to ask the user to select the time zone of the event.
What happens when DST related changes take effect?
That's up to you. You will need to test this thoroughly. In general, there is a period of local time that is skipped, and a period of local time that is repeated.
When it is skipped, you have to decide when to run the event. Options include: 1) before the skipped time, 2) after the skipped time, and 3) not at all. In most cases, the preferred option is to run after the skipped time, by advancing the local time by the DST bias (usually 1 hour). For example, a daily event scheduled to run at 2:30 every day in Pacific time would run at 3:30 on the day of the spring-forward transition.
When it is repeated, you have to decide when to run the event. Options include: 1) at the first occurrence, 2) at the second occurrence, and 3) at both occurrences. In most cases, the preferred option is to run at the first occurrence only. For example, a daily event scheduled to run at 1:30 every day in Pacific time would run at 1:30 PDT, and not at 1:30 PST.
Exceptions to this include dealing with businesses that are open late into the evening and choose to stay open for the repeated hour. For example, a bar, restaurant, or movie theater. It is highly dependent on the specific use case and the choices made by the specific business.
Will library like moment.js will help in this scenario?
Not from a scheduling perspective, no. It can help with parsing, formatting, and validating input though. You might also use moment-timezone to help with selecting the event's time zone. If you were running this with node.js on the back end, then perhaps there would be more benefit.
The biggest challenge is actually one you have not talked about, which is maintaining the time zone data on your server. In your C# code, I recommend using Noda Time for this, instead of TimeZoneInfo. You can then update the tzdb data yourself as needed. You also need to think about the workflow of rescheduling the UTC instants of each occurrence, in the case that a time zone has changed its offset or daylight saving time dates.

Print the time for a given location

Supposing I have
a date (i.e. an UTC timestamp),
a location (e.g. "Paris") that I may encode as I wish (and which isn't the one of the browser),
no permanent internet access
then what can I do if I want to format my date for this specific location, correctly dealing with daylight saving time when/if it occurs ? I'd prefer a standard based solution. I expect the solution to either include a reliable table of some sorts or to call some browser/computer magic.
Of course, as the offset is dependent of the moment, I can't just store the location as an offset.
Here are 2 points which ease the problem :
I won't deal with dates before 2010
if some country decides to change the rules regarding its timezone, it's acceptable for me to release a new code/library
Have a look at moment.js which support localization in a pretty nice way as well as time zones.
For the location issue, I would say you will have a really hard time solving that without an Internet connection. I would say the only way to solve it is to have your users enter a country (and maybe time zone) manually.

Categories

Resources