Using timezone with Angular-UI Bootstrap Timepicker - javascript

I don't know of a simple way to describe this, so this description will be kind of long. Apologies beforehand.
Okay, imagine you live Chicago and you own a business. You write a web app such that you can make an online schedule for your employees that they can check to see when they work each week. Ie, you select a date (in this instance with Angular-UI Bootstrap Datepicker), then you pick to pick a time (using Timepicker) and set an employee to work at that time.
Now, one week you need to go out to California for a business trip. However, you still need to make the schedule out for the next week while you're out of town. Because javascript dates always adjust to local time, if you put "Jake works at 8 pm" on the schedule while you're in California when Jake logs in to look at it, he will see that he works at 10 pm because the 8 pm local California time is 10 pm local CST time.
So, you want all dates and times chosen in your schedule maker to always been in your "home" time zone. IE, no matter where you are, if you set "Jake works at 8 pm", it will always show up as 8 pm CST.
Okay, that's the basic setup. I have all of that working using a little bit of a hacky workaround server side after the "Jake works at 8 pm" message gets sent over. I pull the month, date, year, hours, and minutes out of the sent time, use moment-timezone.js to make a new moment with that date/time but in my "home" time zone, then I convert that new moment into UTC and save it to the DB.
So, back to the client side. I have 3 pages. "New Schedule", which sends the schedule off to the server where it does all the transformation stuff. Then a "View Schedule" page, where I get all of those UTC times back and display them in my 'home' timezone using
Date.toLocalString('en-US', {set of locale options including timeZone: 'America\Chicago'})
So, my "New Schedule" and "View Schedule" pages are working fine. All of the times get remade as a CST time using the exact input time, then converted to UTC. Then the display view outputs them as the correct timezone.
Now, my problem is the last page. My "Edit Schedule" page for making changes to a schedule that's already been saved.
I can't figure out a way to re-adjust my times after they come back from the server to the edit page. So, in this instance, I originally put in "Jake works at 8 pm (and I was in PST when I made it)", which gets converted to "Jake works at 8 pm CST", which gets converted to "Jake works at 15:00 UTC" and saved. Now, my 'View Schedule' page pulls that information, when I load that into the model for my Timepicker, it takes that 15:00 UTC and loads the time picker with 6 pm PST because I'm still in Cali while trying to edit the schedule.
I can't figure out a good way to deal with this. Or maybe there's a better time picker widget I could use that lets you set a default timezone from which it parses the ng-model Date object? I don't know, any ideas would be appreciated!

Related

Javascript - Storing Date as another timezone and parsing it back

The context
I've got an application that lets an admin configure a timezone for their company. Other users, then, can modify the schedule of the company, but it should be always saved with the company's timezone.
This data needs to be stored in UTC in the server, and whenever someone gets it back it needs to be displayed with the company's timezone time.
For example:
Admin sets timezone to "Europe/Madrid" (GMT +01:00).
User A, in timezone "America/Sao Paulo" (GMT -03:00), sets the Schedule to 09:00 - 15:00 (two dates).
The schedule needs to be sent to service in UTC as if the user was in 'Europe/Madrid'.
Service stores the date in UTC
After that, someone in timezone "Europe/Athens" (GMT +02:00) visits the page and they have to see the time as if they were in "Europe/Madrid". So, in this case, 09:00 selected in "America/Sao Paulo" should be stored as "08:00 UTC" (Madrid timezone).
What I need
Basically, I need the time, no matter what is the timezone, to be displayed as if the user was always in the company's timezone, and whenever someone saves the schedule time, I need it to be saved as if they also were in "Europe/Madrid".
Also, the displayed time shouldn't change in DST, as the schedule will be always the same for all the year. So, the user should see all year the "09:00 - 15:00" schedule.
Keep in mind that the server uses SSR, and this means that in the first render we do not know the local timezone of the user who's going to see the data.
What I've tried
I've tried libraries such as "date-fns-tz" and "moment-tz" to convert the dates, but they do not work for the intended, as whenever I parse it to UTC they do it ok but when I try to parse it again to the desired timezone they do not work as expected.
I've tried "countries-and-timezones" library to get the timezone offset and try to manually adjust the dates, but I keep getting messed up by the server's local timezone (which I suspect is the reason why the other libraries didn't work as expected either).
Is there some way I can achieve that?
Thank you.
Basically you'll want to forget about the user's local timezone. America/Sao Paulo should play absolutely zero role in any of this. When the user enters "9:00" in the browser, you just want that to be "9:00" and nothing else. Since the company's timezone is Madrid, you want the input "9:00" to be interpreted as "9:00 Madrid". You can do that either client-side or server-side. But at no point do you want any conversion going on from Sao Paulo time to Madrid time.
Secondarily, you'll want to be very clear what you're storing in the database and what you'll do with this information later. To be clear, what does not work and what you need to avoid is this:
user enters "9:00"
you store 2022-12-01T08:00:00Z in the database
you automatically generate future dates like 2023-05-01T08:00:00Z from it
That generated date in May will be 10:00 Madrid, not 9:00.
You pretty much have two choices:
store just "9:00 Madrid" in the database, i.e. a description of a rule that you can later use to generate times
generate concrete timestamps in the Madrid timezone, convert them to UTC, then store them
Which one is more appropriate depends on how you intent to use them. If you want concrete timestamps in your database to query by, then you need to follow these steps:
get input "9:00 Madrid"
create a concrete date 2022-12-01T09:00:00+01:00
convert it to UTC 2022-12-01T08:00:00Z to store it
generate a future date by adding days/weeks/months to it, keeping the time value the same, e.g. 2023-05-01T09:00:00+02:00
convert it to UTC 2023-05-01T07:00:00Z to store it
for display, convert the UTC date to the company's timezone, and display it in that timezone; i.e. the user's local timezone plays absolutely no role (right?)
To do any time arithmetic, you basically want to construct new dates by combining parts of the existing date, in order to avoid changes to the time-of-day. The details will depend on the exact library being used, but in pseudocode it's something like:
var a = new Date(2022, 12, 1, 9, 0, 0, 'Europe/Madrid')
var b = Date.combine(a.date.add(6, 'months'), a.time, a.timezone)
// 2023-05-01 9:00:00 Europe/Madrid
Hope this helps to clarify things a bit.

iCalendar start time difference

What is this about
I'm developing a web application in NodeJS to display information about the agenda of the users which are synchronized with the central server of my University. For that, I wrote a script that downloads an ICS file every hour to update my local agenda (stored in an SQLite database).
What seems to be the problem
Someone reported to me that some events in their agenda aren't synchronized properly with the University's version, the start time differs. Here's the problem. I have an Event A and an Event B which are both displayed as starting at 6am UTC on the university web page. But, when I retrieve them from the server in iCal format, they are represented as such (I've removed the properties unrelated to my issue) :
DTSTART:20211108T070000Z <-- starts at 7am UTC
DTEND:20211108T083000Z
SUMMARY:Event A
LOCATION:A room
DESCRIPTION:A description
DTSTART:20211025T060000Z <-- starts at 6am UTC
DTEND:20211025T073000Z
SUMMARY:Event B
LOCATION:A room
DESCRIPTION:A description
What I already tried
I've already tried using an open source application (named OpenWebCalendar) that displays iCal events to a calendar from a URL and it displays just like the University agenda. Both *Event A and B start at 6am UTC.
Unfortunately, I couldn't find how the app did it be looking into its source code.
So this problem doesn't come from the University ical file I retrieve.
I've tried looking into the iCalendar specification document to no avail. I also couldn't find any evidence that this was related to a timezone issue as all datetime values set in the ical file are in UTC format.
So, no problem with the Timezones and I can't find a property or specification that would explain this difference and how to fix it.
I've also written a test script in NodeJS in order to retrieve info about the iCal to no avail using node-ical. The start time displayed when retrieving the events are the same as in the file which doesn't help at all.
Here's the redacted code if you are interested :
const ical = require('node-ical')
let body = `
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//SomeAppName/version 1.0
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VEVENT
DTSTAMP:20211010T100331Z
DTSTART:20211108T070000Z
DTEND:20211108T083000Z
SUMMARY:Event A
LOCATION:A room
DESCRIPTION:A description
UID:UniqueCodeA
CREATED:19700101T000000Z
LAST-MODIFIED:20211010T100331Z
SEQUENCE:2128343411
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20211010T100331Z
DTSTART:20211025T060000Z
DTEND:20211025T073000Z
SUMMARY:Event B
DESCRIPTION:A description
UID:UniqueCodeB
CREATED:19700101T000000Z
LAST-MODIFIED:20211010T100331Z
SEQUENCE:2128343411
END:VEVENT
END:VCALENDAR
`
ical.async.parseICS(body, function(err, events){
console.log(events["UniqueCodeA"])
console.log(events["UniqueCodeB"])
})
So, my question is
Is there any iCal specification, properties or any explanation as to why both iCal start times diverge and how to correct them just like OpenWebCalendar does it ?
Welcome to the joys of daylight saving changes and timezones. Somewhere there someone is viewing dates with a timezone set as most people do, this is expected. There are 2 dates there, and it appears one is one side of a daylight saving change and the other is on the other side.
Unlike UTC some timezones have daylight saving and of course timezones don't change from/to daylight saving at the same time, so lots potential for multiple time differences to appear to be inconsistent across events.
If we take London as an example, on the 8 of November 2021, london time is same as UTC time:
https://www.timeanddate.com/worldclock/meetingtime.html?day=8&month=11&year=2021&p1=195&p2=136&iv=0
However on 25 October 2021, at 6am UTC time, London is 7am.
https://www.timeanddate.com/worldclock/meetingtime.html?iso=20211025&p2=195&p3=136
Always check what timezones are set on every device and calendar app and be alert around daylight saving changes.

Moment.format() modifies times according to timezone

I am using Moment.js to represent data coming from backend. In my case I have a date
represented in this format "2015-01-02T00:00:00Z". Then I feed it to Moment.Format()
moment("2015-01-02T00:00:00Z").format('LLL')
what comes out of this is "01/01/2015" , which is a different date.
To give more details, we are facing such bug when the timezone of the computer is set to something else.
So, if I am where I am now, let's say Rome and the timezone is set correctly here, moment.Format() returns the right date "02/01/2015". If instead I change the timezone in the system of my computer and for example I put Lima, then it goes to "01/01/2015". How do I make sure the right date is shown without depending on the timezone?
Thanks in advance!
Oh boy.... here we go again with dates :O
Ok so starting off, take a look at this sentence that you wrote
How do I make sure the right date is shown without depending on the
timezone?
And now I raise you this question:
A greek guy ( me ) wants to date you. I wanna take you to dinner, lets
say this Monday 2019/09/23 20:00:00
Now because I told you that I am greek you can infer by the difference in our time zones that my "Monday 2019/09/23 20:00:00" is actually your "Monday 2019/09/23 12:00:00". And you can show up on time, all though my dinner is actually your lunch.
I hope you get my point from this, now onto your case:
You will either:
Only support people's date when they originate from the same time zone as your developing team ( not cool for a project, but many times a company has no need to communicate dates with people from other timezones)
You will have to provide the TimeZone that your date was "constructed with" to moment, so it can resolve the differences to the local time of each user.
You will convert all dates to UTC, so the server will only "speak" UTC times, while the clients will the be free to convert to their needed time zone. You wont have to provide the "original timezone" because of the convention that your dates are always UTC (which implies the "original timezone" actually to 0 )
I hope the above helps to get you some basic understanding of the dates issue.

How to adjust an array of hours to a preferred timezone?

So a little context, I have an array of 24 arrays -- one for every hour in the day.
So midnight, 0 index, would be [133.00, 234.00] which would indicate 133 actions from 12 - 1230 and 234 actions between 1230 - 1am.
I need to adjust these indexed arrays to account for the user's timezone in a browser with JS, so that if the user is in New York the 0 index (midnight in the user's home turf) is displayed in China's offset (12pm tomorrow, from user's perspective).
I've been trying to think of a solution, I have a simple function for what I've been able to think of
function offsetHourIndex(hourIndex, dataCenterTimeZone) {
let userTime = new Date().setHour(hourIndex)
return moment(userTime).tz(dataCenterTimeZone).hour();
}
How reliable would this approach be?
Your approach has a few problems:
You are assuming that the current date in the local time zone is the correct date for the target time zone. Most of the time, there are two dates active somewhere around the world. For example, 2019-04-02 04:00 in London is 2019-04-01 23:00 in New York. If you just take hour 4 from London but apply it to the current date in New York, you've created a whole new point in time, a day too early.
You assume there will be exactly 24 hours in every day. In time zones that have transitions for daylight saving time or changes in standard time, you may have more or less hours of local time on a the day of the transition.
In the case of a backward transition, there is a period of ambiguous local time. For example, when US Pacific Time moves from PDT to PST in November, the hour from 1:00-1:59 is repeated. If data from both hours are summarized into array element 1, then you will have higher than normal results for that hour. The opposite is true for forward transitions - you will have an hour with no data.
The time zone setting of the server can be a fickle thing. What if you change data centers? What if you move to the cloud? What if you are operating multiple data centers? What if a server administrator thinks all they are affecting by changing the system time zone is the readout on the taskbar or front panel, etc., and then it affects your application? In general one should avoid these things by never relying on the server's local time zone setting.
You can avoid all of these problems by basing everything on Coordinated Universal Time (UTC) - especially the array. Then you can be ignorant of any server time zone setting, and just base everything off the current UTC day, which is the same all over the world.
This will give you the local hour from the given UTC hour in your index:
var localHour = moment.utc({hour: hourIndex}).local().hour();
You do not need moment-timezone for the above recommendation.
However, if you really feel like you need to convert from a specific time zone to the browser local time, then you would use moment-timezone like this:
var localHour = moment.tz({hour: hourIndex}, timeZoneName).local().hour();
Note when you do this, you also have another problem - not every time zone is offset by a whole number of hours. For example, India uses UTC+05:30. There are many that are :30 and a few that are :45. By tracking hours only, you're not providing enough information to properly convert to the correct local hour. Your results may be off by one.
It seems reasonable. And the code should work as long as you have the properly formatted inputs. I like the brevity and clarity of the function. Any reason you are concerned about reliability?
You might mention in your question that you are using the moment and moment-timezone packages here to derive your data via its functions (moment & tz) on this line of code:
return moment(userTime).tz(dataCenterTimeZone).hour();
Your function may appear a bit cryptic without the imports in your example for folks reading here to understand, such as :
import * as moment from 'moment';
import 'moment-timezone';

How to find the client machine time zone using ASP.NET

I need to find the time zone of the client machine using ASP.NET (C#) or JavaScript. What are the different time zones that are available all over the world and how to convert the date and time based on the users time zone.
Please provide some suggestions or sample coding to change the time based on the time zone.
You cannot find client time zone settings from ASP.NET.
You can use JavaScript to tell the current time, but there are several time zones that can be synchronized at any given time.
In Chrome, you can get the time zone from the JavaScript date object. There's no specific function for it, from what I've found, but the code
(new Date()).toString()
will yield something like
Mon Apr 18 2011 08:58:59 GMT+0200 (W. Europe Daylight Time)
In websites, the best approach I've found has been to have a setting for each user to specify the time zone to display all times in. If the JavaScript getUtcOffset gives a different offset than what is expected for the user's time zone, I'll show a notice for the user to review their settings. If time zone can be guessed from the date (which I've only found to be the case in chrome), I'll suggest that time zone, but I still resort to a select box for the user to manually pick the time zone.
Even so, it is possible to have the wrong time zone setting, without the script noticing it, because for a great part of the year, the two time zones may be perfectly synchronized.
Once you have a time zone (you can enumerate them all with System.TimeZoneInfo.GetSystemTimeZones()), you can convert UTC dates with System.TimeZoneInfo.ConvertTimeFromUtc and System.TimeZoneInfo.ConverTimeToUtc, respectively.

Categories