Adding hours and minutes to a date with JavaScript - javascript

I am building a meeting calendar based on time zones around the world. My problem is how to add or subtract the time zone from the user selected date in JavaScript.
For example, on the select form, the user will select the date from a form: I would then get the results and convert to a date as below...
var ldSelectDate = new Date(document.form1.year.value,
document.form1.month.value,
document.form1.day.value);
I would like to add 12 midnight to this object.
I then read in an XML that gets the time zone difference in a string between two cities: such as "+0430" for Kabul or "-0400" for New York (on daylight savings time). This is based on GMT,.
I then calculate the time zone difference between the two cities: which will return the string of "830". (I assume I have to return this as a date object?). I got this part done returning a string. I'm working with strings.
I then want to loop through the 24 hours of the day, set Kabul at 12 midnight and then loop through. I can most likely figure this out - that is, set the date with the whole hours as I loop.
My problem is painlessly subtract the "830" from Kabul to see what the meeting time will be in New York.
It will be ideal if I can just subtract the hours and the minutes from the Kabul time. I noticed on here someone subtracting the hours in JavaScript, but not the minutes. BTW, that post didn't work for me.
I did this with strings without the minutes, but I mess up with the minutes. There has to be an easier way.
I would take a solution in either native JavaScript or jQuery.
Again, I need to subtract/add the time zone difference in hours and minutes to a certain date.

date.setMinutes(date.getMinutes()+minutesToAdd);
The above code will set your date object ahead by the amount of minutes in the minutesToAdd variable

Easiest would be to calculate the minutes for that time delta then do a minutes delta.
date.setMinutes(date.getMinutes() - (hours*60+minutes))

Related

Simplest way to find out how many milliseconds until a specific time in a specific timezone (taking DST into account)?

I have a piece of code which finds the difference between two dates(in the format of yyyy-MM-dd hh:mm:ss) . This code is run in multiple servers across the globe. One of the two dates is the current time in that particular timezone where the code is being run(server time) and another is the time obtained from a database. if the difference between these two times is greater than 86400 seconds(1day), then it should print "invalid" else, it should print "valid".
Problem im facing with the code is when I run it on my local, its working fine, but when i deploy it onto a server in US, its taking GMT time into consideration and not local time.
Wherever the code is run, I want the difference between current time and time fetched from the database, and if its greater than 86400 seconds, i want to print invalid. How to achieve this in java?
PS: I tried with Date object, but its considering GMT only everywhere.
I would use GMT everywhere and only convert to the local times for display purposes.
To find the difference, convert both times to the same timezone (say GMT) and take the difference.
You can do it by the below example code.
Date date = new Date();
DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
formatter.setTimeZone(TimeZone.getTimeZone("CET"));
Date date1 = dateformat.parse(formatter.format(date));
// Set the formatter to use a different timezone
formatter.setTimeZone(TimeZone.getTimeZone("IST"));
Date date2 = dateformat.parse(formatter.format(date));
// Prints the date in the IST timezone
// System.out.println(formatter.format(date));
Now compare date1 with date2
First, I concur with Peter Lawrey's answer up there. It is usually good practice to store all time in the database for a single zone, and render it with offset for the user based upon the user's locale.
To find the difference, use the method getTime() to get the time in milliseconds from the epoch for each date. The calculation for the difference of 1 day is then 86400 * 1000 milliseconds. Or, perhaps, store the time in milliseconds from epoch in the database, and use a DB procedure/function at the time of retrieval.
Hope this helps.

Add a duration to a repeating event's start time so that it's end is always the same time (i.e 2pm to 4 pm)

I have a bunch of rrules (implemented in rrule.js) that gives me an array of event start times (see the demo). rrule.js doesn't actually provide the concept of an event duration or endtime... So it can tell me the precise date when the millionth occurrence of a repeating event will start but not when it will end. Turns out I actually want to know when an event ends so I'll have to get creative. As far as I see it I've got two options
DB SIDE: Store an rrule string + an event duration.
CLIENT SIDE: Reconstitute events start date array from rrule string. Only start times would be known and end times would be calculated by adding the duration as an offset to each start time in the array.
DB SIDE: Store a modified rrule string which encodes an endtime.
CLIENT SIDE: A special wrapper function reads the modified rrule string and reconstitutes it as two date arrays; one representing event start times and the other end times.
Option 1 seems easier but I suspect it will run into problems with daylight savings. For example, say I've an event that is every Tuesday from 6pm to 2 am Wednesday. In that case I'd store a duration of 8 hours in my database alongside that stringified rrule. Now let's fast forward to any 6pm Tuesday in the future. Does my event always end on Wednesday at 2am (or does that 8 hour duration sometimes make my event end at 1am or 3am)? How do I get it to always end at 2am?
... If you know the answer then just stop reading here.
How I've seen others handle duration offset
According to Kip in How to add 30 minutes to a JavaScript Date object? the smart way to offset a date time is to use a fancy library like moment.js.
He emphasizes that point by showing how easily things go wrong using non fancy date time libraries (showing how a naive minute offset function fails due to daylight savings)
function addMinutes(date, minutes) {
return new Date(date.getTime() + minutes*60000);
}
addMinutes(new Date('2014-11-02'), 60*24) //In USA, prints 11pm on Nov 2, not 12am Nov 3!
But something weird happens for me. The function above was supposed to output 11pm on Nov 2 - which is the wrong answer i.e. it was supposed to fail because of daylight savings. When I run it, it actually outputs the right time 12am on Nov 3 (note: I'm in Chicago/Central time).
When I compare the output of his naive function to the output of moment.js and luxon.js, I get the same answer as you can see in this observable notebook.
Scratching my head
What's more, if using luxon or moment, when you add a days worth of minutes to 2014-11-02 you get2014-11-03T00:00:00.000Z but if you just directly add a day to 2014-11-02 you get 2014-11-03T01:00:00.000Z - it's an hour off.
So am I better off pursuing option 2?
Now let's fast forward to any 6pm Tuesday in the future. Does my event always end on Wednesday at 2am (or does that 8 hour duration sometimes make my event end at 1am or 3am)? How do I get it to always end at 2am?
The standard Javascript Date object automatically handles the daylight savings shift for you. Even if you add 8 hours to a date at 6pm the day before daylight savings, the new date will still end at 2am the next day.
Incidently, I implemented duration support in rSchedule and since it supports both the standard javascript Date as well as moment/luxon dates, you can test a recurring event with a duration using either library and see that they both produce the same result.
This example can be seen on stackblitz.
import { Schedule } from '#rschedule/rschedule';
import { StandardDateAdapter } from '#rschedule/standard-date-adapter';
// This example will also work with `moment`, `moment-timezone`, and `luxon`
// (assuming you import the proper date adapter -- see rSchedule docs)
const schedule = new Schedule({
rrules: [
{
start: new Date(2019,9,10,18),
frequency: "DAILY",
duration: 1000 * 60 * 60 * 8,
count: 30
}
],
dateAdapter: StandardDateAdapter,
});
schedule.occurrences().toArray().forEach(adapter => {
console.log(
{
start: adapter.date.toLocaleString(),
end: adapter.end.toLocaleString(),
}
)
})
Turns out I actually want to know when an event ends
To find out when this event ends, you could do:
const iterator = schedule.occurrences({ reverse: true })
const { end } = iterator.next().value
This trick would only work with an event that actually has an end date (so not an event with infinite occurrences).
I wrote the original answer you are referring to about a decade ago. Seven years later, I made an edit, changing new Date(2014, 10, 2) to new Date('2014-11-02'). I thought this would be easier to read (because you don't have to explain that the months in that version of the constructor start at 0 instead of 1). But as #RobG pointed out, formatting in this way causes it to be parsed as UTC. I've gone back and fixed this now (thanks for pointing it out).
To get to your "scratching my head" part of your question:
What's more, if using luxon or moment, when you add a days worth of minutes to 2014-11-02 you get 2014-11-03T00:00:00.000Z
The Z at the end of that timestamp means it is in UTC, and UTC does not observe daylight savings time. So if you start with 2014-11-02T00:00:00.000Z, and add 24 hours, you get 2014-11-03T00:00:00.000Z. When you add hours/minutes/seconds, there's no need to worry about daylight saving time.
but if you just directly add a day to 2014-11-02 you get 2014-11-03T01:00:00.000Z - it's an hour off.
In this case what is happening is you are starting with 2014-11-02T00:00:00.000Z, but when you tell the library to add one day, and you don't specify a time zone, the library is assuming you are in your local time zone, so it adds one local day. Because you cross a DST boundary, that day is 25 hours long, and when you print it as an ISO timestamp in UTC, you end up with 2014-11-03T01:00:00.000Z (25 hours later).
Time zone stuff is hard, even if you are using a library. Most people can get by for a long time not knowing or caring that for many users one day a year is 25 hours long. But if these edge cases will matter to you, the best approach is to play around with them like you're doing, and make sure you really understand what is happening and why.

Quickest way to add minutes and seconds to string formatted 'h:i:s: A'

I'm using Bootstrap-Timepicker to collect a time field. The user will select the the start time with the timepicker widget as well as a number of iterations and a time interval. I want to add the selected interval to the time for the given number of iterations.
For example: if the User select 11:40:00 PM and wishes to ad 10 minutes and 15 seconds 4 times, then I need to iterate through the following time values:
11:40:00 PM
11:50:15 PM
12:00:30 AM
12:10:45 AM
Bootstrap-timpicker doesn't provide an easy way to manipulate the time value like this that I know of, and when I get its value it returns a String formatted h:i:s A as in the example above.
I figure there must be an easier way to this than the way I plan to solve this problem currently which would be to parse the value and run if conditions to check to see if the hour or AM/PM roll over. Should I convert this string to a datetime, and if so, how? I'm open to other suggestions as well.
Put in the time, with a date, into the JavaScript date object like this:
var myDate = new Date('11:40:00 PM 2015-09-23');
Then, add minutes
myDate.setMinutes(myDate.getMinutes() + 10);
Then add seconds
myDate.setSeconds(myDate.getSeconds() + 15);
And this can be repeated 4 times
You can get the time back out in a format you'd like, just look at the docs
You can also add the time at once, but this is less pretty I think
myDate.setTime(myDate.getTime() + 615);

Reliable way to convert javascript timestamp into a date tuple

I want to convert javascript time stamps to erlang dates. I am using the qdate library to help me do that since it also provides functions for date arithmetic.
Calling it's to_date function first before midnight and then after midnight results in time displacement of 24 hrs. For example:-
qdate:to_date(Timestamp div 1000).
%% {2015,5,2} before midnight
qdate:to_date(After_midnight_Timestamp div 1000)
%%{2015,5,2} after midnight should be 3 instead of 2
I googled around a bit and found this in the erlang calender docs
The time functions local_time/0 and universal_time/0 provided in this module both return date and time. The reason for this is that separate functions for date and time may result in a date/time combination which is displaced by 24 hours. This happens if one of the functions is called before midnight, and the other after midnight. This problem also applies to the Erlang BIFs date/0 and time/0, and their use is strongly discouraged if a reliable date/time stamp is required.
I am having trouble understanding this. Which one of the functions from local_time/0 and universal_time/0 always gives the correct results? By correct I mean I want the right date to be shown after midnight. The resolution of the time is only {y,m,d}. Don't care for hours, minutes and seconds or anything finer than that.
So how do I reliably convert a javascript timestamp to a date in erlang?
Looks like it was just a timezone issue :) Since I was working with javascript timestamps the default timezone of the javscript time stamp is my localtimzone which is "IST". Now internally when qdate sees an integer in qdate:to_date(Timestamp). it automatically selects a UTC timezone for it. Relevant code on line 256:-
raw_to_date(Unixtime) when is_integer(Unixtime) ->
unixtime_to_date(Unixtime);
%% other clauses
and on line 654
unixtime_to_now(T) when is_integer(T) ->
MegaSec = floor(T/1000000),
Secs = T - MegaSec*1000000,
{MegaSec,Secs,0}.
unixtime_to_date(T) ->
Now = unixtime_to_now(T),
calendar:now_to_datetime(Now).
The final clue comes from the erlang calendar documentation itself
now_to_datetime(Now) -> datetime1970()
Types: Now = erlang:timestamp()
This function returns Universal Coordinated Time (UTC) converted from the return value from erlang:now().
So the solution to this problem was to simply supply an IST string with qdate:to_date() like so:-
qdate:to_date("IST",Timestamp div 1000)
and it started returning correct dates. I wasn't sure of the solution so I ran a test with qdate:to_date(erlang:now()) and the value returned was exactly 5:30 hrs behind my clock time. So it seems that supplying the timezone string works :)

Save time in mongodb

I have tried to save a specific time into my mongodb database
with the javascript date object like:
var currenttime = new Date();
currenttime.setHours(14);
currenttime.setMinutes(37);
db.test.insert({time: currenttime});
however I have noticed that not only are the hours and minutes saved,
but also the date. I am searching for a way to only save the hours and
minutes, but in a way that I can still do less than greater than operations
on it. Is there a way to do this?
MongoDb Date is only 64bits, on the other hand if you will store your time as just 2 32 bit integers (hours and minutes) you will be already using these 64 bits. If you will save them as a 4 letters string, it will be even more.
So you can not gain space advantage. But you will lose advantage of querying your data. It will be harder to find all elements that are bigger than particular time with 2 numbers format and even harder with strings.
So I would save them as dates. If you really need only time - and need to query by this time, you can do the following trick: make all dates the same. For example:
var a = new Date(); // gives current date and time (note it is UTC datetime)
a.setYear(2000);
a.setMonth(0);
a.setDate(1);
db.test.insert({time: currenttime});
This way all the elements will have the same date and different time. In such a way you sort them properly. Also if you need to find all the elements where time is smaller than a particular time, you can quickly create a date object with year/month/day (2000/0/1) and query your data properly.
You can consider to save number of minutes as an integer field.
For example, 8:30 will be converted as 8 hour * 60 minutes + 30 minutes = 510 minutes. Save 510 as an number in MongoDB.
Basically you can try these two options to save time:
Save time as type: String
const userInput = '05:20';
const hours = userInput.slice(0, 2);
const minutes = userInput.slice(3);
Save date time in type: Date
But in second option you have to create Date object and set hours and minutes:
const date = new Date(dateString);
date.setHours(hours, minutes);

Categories