Calculate end date with number of weeks and disabled dates - javascript

I have some data as so from a datepicker:
$disabled_dates = "08/10/2017, 08/17/2017";
$start_date = "08/03/2017";
$num_of_weeks = "20";
I am trying calculate the end date based off the $start_date and $num_of_weeks
I know this is possible with new Date() but i'm not sure how to account for the $disabled_dates.

strtotime() is an amazingly useful function for something like this.
It accepts a wide variety of natural language and date/time inputs.
20 weeks from exactly now
echo date('c',strtotime('+20 weeks'))."\n";
20 weeks from the start of that day
echo date('c',strtotime('08/03/2017 +20 weeks'))."\n";
Your answer in php:
$disabled_dates = "08/10/2017, 08/17/2017";
$start_date = "08/03/2017";
$num_of_weeks = "20";
$the_end = strtotime($start_date.' GMT +'.$num_of_weeks.' weeks');
//make all the disabled dates into timestamps for easy comparison later
$disabled_dates_array = array();
foreach(explode(',', $disabled_dates) as $date){
$disabled_dates_array[] = strtotime(trim($date).' GMT');
}
//now compare and delay the end date if needed
foreach($disabled_dates_array as $timestamp){
//if there was a disabled date before the end, add a day's worth of seconds
//strtotime() returns false if it can't parse the date, so make sure it's truthy
if($timestamp && $timestamp <= $the_end){
$the_end += 86400;
}
}
$enddate = date('m/d/Y',$the_end);
Edit 1: added GMT to all strtotime() conversions, to avoid issues with daylight saving times changing the amount of seconds between dates. Some days are 23 hours and some are 25 because of daylight saving time. Leap seconds are not an issue in unix time.
Edit 2: Answer in javascript:
var disabled_dates = "08/10/2017, 08/17/2017";
var start_date = "08/03/2017";
var num_of_weeks = "20";
var the_end = Date.parse(start_date + ' GMT') + parseInt(num_of_weeks)*7*86400*1000;
//in javascript Date.parse is similar to php's strtotime,
//but it returns milliseconds instead of seconds
disabled_dates = disabled_dates.split(", ");
for(var i = 0, len = disabled_dates.length; i < len; i++){
disabled_dates[i] = Date.parse(disabled_dates[i] + ' GMT');
if(disabled_dates[i] && disabled_dates[i] <= the_end){
the_end += 86400000;
}
}
the_end = new Date(the_end);
var enddate = ('0' + (the_end.getUTCMonth() + 1)).substr(-2) + '/' + ('0' + the_end.getUTCDate()).substr(-2) + '/' + the_end.getUTCFullYear();
console.log(enddate);
Here I ran into a problem with daylight saving time as
Sun Oct 29 2017 00:00:00 GMT+0100 (GMT Daylight Time) + 24 hours =
Sun Oct 29 2017 23:00:00 GMT+0000 (GMT Standard Time)
So adding ' GMT' (GMT Standard Time) at the end of the dates is important, otherwise the results may be off by a day.
This video gives some insight into how keeping time can become complicated.

I'm not sure if there is an easier way, but that's who I would do it:
// Put dates into array or split the string
$disabled = array(new DateTime('2012-08-01'),new DateTime('2017-09-19'));
$end_date = $date->add(new DateInterval('P'.$num_of_weeks.'D'));
$range = new DatePeriod($start_date, new DateInterval('P1D'),$end_date);
// remove disabled days
foreach($range as $date){
if(in_array($date,$disabled))
$end_date = $end_date->sub(new DateInterval('P1D'));
}
The Code is not tested but it should work. If not, let me know xD.
Hope that helps.

Related

Javascript Converting Ints to Time?

For a project app I'm making, a homework keeper, I need to be able to turn a number like 10 into a month like october, then do this with year, month, day, and time. Then I need to save it all in a date. How do I do this? I have been looking everywhere and cannot find how to do it.
It looks like you're looking for the Date() constructor.
var month = 10;
var day = 17;
var year = 2017;
var hour = 8;//Use the 24 hour clock for times in the PM
var minutes = 36;
var date = new Date(year, month-1, day, hour, minutes);//Outputs October 17th, 2017 at 8:36am in your local timezone
You have to subtract 1 from the month because January starts at 0, not 1.
Alternatively, I like to use moment.js for the flexibility depending on use, so you could instantiate it like this:
var date = moment(year + '-' + month + '-' + day + ' ' + hour + ':' + minutes, 'YYYY-M-D H:m');//Because you are using numbers/integers, none of them will have preceding zeroes
Take a look at the Date constructor - I think it doesn everything you need.
Your biggest gotcha is that months are 0-indexed so you'll actually turn 9 into October. Also beware that if you don't initialise Date with anything, it'll assume you mean now.
var date = new Date();
date; // -> Tue Oct 17 2017 13:34:49 GMT+0100 (GMT Daylight Time)
date.setMonth(10); // -> 1510925689970
date; // -> Fri Nov 17 2017 13:34:49 GMT+0000 (GMT Standard Time)

How can I convert string formatted UTC dates without offset to local time in JavaScript?

I am getting a string formatted date with UTC timezone. I need to convert this date time in user's current time zone using jquery or javascript.
I am getting this:
9:43pm 16/10/2015 //this is UTC time, I am getting this via an ajax call
I need to convert it to this:
12:00pm 16/10/2015 //whatever time by that location
If you can pick that format apart, or get a standard format JavaScript can parse - you can convert it to a Date object. I'm not seeing an offset on that date which is problematic when JavaScript tries to parse it. Assuming that is all you have, we can force a UTC date with the following...
// ------- new Date(Date.UTC(year, month, day, hour, minute, second))
var date = new Date(Date.UTC(2015, 9, 16, 21, 43, 0));
console.log(date) // Fri Oct 16 2015 15:43:00 GMT-0600 (Mountain Daylight Time (Mexico))
note that month in Date.UTC is zero based e.g. October would be 9
new Date(value) would do this for us automatically if the format is correct - where value is the actual date value you receive - but that format will not parse as is. If there is no way around that format, you can manipulate it to work in the above example. Here is an untested algorithm for your example...
var formatted = '9:43pm 16/10/2015'
function createDateUTC(formatted) {
var hourOffset = formatted.split(' ')[0].split(':')[1].match(/[a-zA-Z]+/g)[0] === 'pm' ? 12 : 0
var year = parseInt(formatted.split('/').pop());
var month = parseInt(formatted.split('/')[1]) - 1;
var day = parseInt(formatted.split('/')[0].split(' ').pop());
var hour = hourOffset + parseInt(formatted.split(' ')[0].split(':')[0]);
var minute = parseInt(formatted.split(' ')[0].split(':')[1]);
return new Date(Date.UTC(year, month, day, hour, minute, 0));
}
var myDate = createDateUTC(formatted);
JSFiddle Link - working demo
Check out the UTC() and Date Object docs for more info
Additionally, to get the exact format you want, we can introduce some more functions which will give us the 12:00pm 16/10/2015 format
function formatAMPM(date) {
var hours = date.getHours();
var minutes = date.getMinutes();
var ampm = hours >= 12 ? 'pm' : 'am';
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
minutes = minutes < 10 ? '0'+minutes : minutes;
var strTime = hours + ':' + minutes + '' + ampm;
return strTime;
}
function formatMMDDYYYY(inputFormat) {
function pad(s) { return (s < 10) ? '0' + s : s; }
var d = new Date(inputFormat);
return [pad(d.getDate()), pad(d.getMonth()+1), d.getFullYear()].join('/');
}
console.log(formatAMPM(myDate) + ' ' + formatMMDDYYYY(myDate));
// Mountain Daylight Time => -- 3:43pm 16/10/2015
JSFiddle Link - formatted example
I'd reccoment looking into Moment.js if you plan to do heavy date formatting and manipulation.
Overall - the best solution to this would be to return an acceptable format from the server, resolve it to local time natively e.g. new Date(), and use a robust formatting library as opposed to rolling your own to display it how you wish.
You should process that string a little bit to extract year, month, day, hour and minute.
Then you can create a local date with that UTC date using this:
var time = new Date ( Date.UTC('year', 'month', 'day', 'hour', 'minute') );
In my case, '9:43pm 16/10/2015' returns: 'Mon Nov 16 2015 07:43:00 GMT-0200 (Hora de verano de Argentina)'.

How To add number of month into the given date in javascript?

I want to add month into the select date by the user.
startdate=document.getElementById("jscal_field_coverstartdate").value;
now I want to add 11 month from the above startdate. How to do that.
date format = 2013-12-01
Without the date format it is difficult to tell, however you can try like this
add11Months = function (date) {
var splitDate = date.split("-");
var newDate = new Date(splitDate[0], splitDate[1] - 1, splitDate[2]);
newDate.setMonth(newDate.getMonth() + 11);
splitDate[2] = newDate.getDate();
splitDate[1] = newDate.getMonth() + 1;
splitDate[0] = newDate.getFullYear();
return startdate = splitDate.join("-");
}
var startdate = add11Months("2013-12-01");
alert(startdate)
JSFiddle
If your startdate is in correct date format you can try using moment.js or Date object in javascript.
In Javascript, it can be achieved as follow:
var date = new Date("2013-12-01");
console.log(date);
//output: Sun Dec 01 2013 05:30:00 GMT+0530 (India Standard Time)
var newdate = date.setDate(date.getDate()+(11*30));
console.log(new Date(newdate));
// output: Mon Oct 27 2014 05:30:00 GMT+0530 (India Standard Time)
In above lines, I have used 30 days per month as default. So you will get exact 11 month but little deviation in date. Is this what you want ? You can play around this likewise. I hope it help :)
For more about Date you can visit to MDN.
You can do it like this:
var noOfMonths = 11
var startdate = document.getElementById("jscal_field_coverstartdate").value;
startdate.setMonth(startdate.getMonth() + noOfMonths)
Try this:
baseDate.setMonth(2);
baseDate.setDate(30);
noMonths = 11;
var sum = new Date(new Date(baseDate.getTime()).setMonth(baseDate.getMonth() + noMonths);
if (sum.getDate() < baseDate.getDate()) { sum.setDate(0); }
var m = newDate.getDate();
var d = newDate.getMonth() + 1;
var yyyy = newDate.getFullYear();
return (yyyy+"-"+m+"-"+d);
Notes:
Adding months (like adding one month to January 31st) can overflow the days field and cause the month to increment (in this case you get a date in March). If you want to add months and then overflow the date then .setMonth(base_date.getMonth()+noMonths) works but that's rarely what people think of when they talk about incrementing months.
It handles cases where 29, 30 or 31 turned into 1, 2, or 3 by eliminating the overflow
Day of Month is NOT zero-indexed so .setDate(0) is last day of prior month.

Need to display local times over DST transitions using Javascript Date Object

I am trying to output a series of times in hour (on the hour) intervals within Javascript (so inside a web browser such as Firefox). This series of times will overlap the short day (losing an hour in spring) and long day (gaining an hour in autumn). The output I'm looking for is in local time, i.e. with timezone and DST offsets applied. So for example, in the UK we have a missing hour from 01:00 to 01:59 on the short day such that the output would be:
00:00, 02:00, 03:00
And on the long day we have an extra hour from 01:00 to 02:00 such that the output would be:
00:00, 01:00, 01:00, 02:00, 03:00
I have already found these two brilliant answers that highlight some pitfalls and address part of my problem:
Daylight saving time and time zone best practices
Javascript Date objects and Daylight Savings Time
But the real difficulty is in making javascript aware of this missing and extra hour (so to speak) as identified in the second question mentioned above.
I think a potential solution to this would be to operate in UTC (aka GMT) and just do a conversion to local time but I'm struggling to see how I could do this.
Does anyone have any ideas about how to achive what I'm after?
If you have a fixed timezone, the following javascript code seems to work (tested on the last chrome version and firefox 6) :
// set the date to 11 / 04 / 2012 at 00:00 UTC
var date = new Date(1331424000000);
for(var i = 1; i <= 12; i++) {
$('.data-dston').append(' ' + date.getHours() + ':00, ');
date = new Date(date.getTime() + 3600000)
}
// set the date to 04 / 11 / 2012 at 00:00 UTC
var date = new Date(1351987200000);
for(var i = 1; i <= 12; i++) {
$('.data-dstoff').append(' ' + date.getHours() + ':00, ');
date = new Date(date.getTime() + 3600000)
}
Here's a JSFiddle : http://jsfiddle.net/Vsd2A/3/ to see the code in action !
Adapting what Krtek has come up with (for my timezone - UK) I now have the following:
// set the date to 27 / 03 / 2011 at 00:00 UTC
var date = new Date('27 Mar 2011 00:00');
for(var i = 1; i <= 12; i++)
{
$('.data-dston').append(' ' + date.getHours() + ':00, ');
date.setTime(date.getTime() + 3600000);
}
// set the date to 30 / 10 / 2011 at 00:00 UTC
var date = new Date('30 Oct 2011 00:00');
for(var i = 1; i <= 12; i++)
{
$('.data-dstoff').append(' ' + date.getHours() + ':00, ');
date.setTime(date.getTime() + 3600000)
}
Which has the benefit of not having to construct a new object on each iteration.

How to ignore user's time zone and force Date() use specific time zone

In an JS app, I receive timestamp (eq. 1270544790922) from server (Ajax).
Basing on that timestamp I create Date object using:
var _date = new Date();
_date.setTime(1270544790922);
Now, _date decoded timestamp in current user locale time zone. I don't want that.
I would like _date to convert this timestamp to current time in city of Helsinki in Europe (disregarding current time zone of the user).
How can I do that?
A Date object's underlying value is actually in UTC. To prove this, notice that if you type new Date(0) you'll see something like: Wed Dec 31 1969 16:00:00 GMT-0800 (PST). 0 is treated as 0 in GMT, but .toString() method shows the local time.
Big note, UTC stands for Universal time code. The current time right now in 2 different places is the same UTC, but the output can be formatted differently.
What we need here is some formatting
var _date = new Date(1270544790922);
// outputs > "Tue Apr 06 2010 02:06:30 GMT-0700 (PDT)", for me
_date.toLocaleString('fi-FI', { timeZone: 'Europe/Helsinki' });
// outputs > "6.4.2010 klo 12.06.30"
_date.toLocaleString('en-US', { timeZone: 'Europe/Helsinki' });
// outputs > "4/6/2010, 12:06:30 PM"
This works but.... you can't really use any of the other date methods for your purposes since they describe the user's timezone. What you want is a date object that's related to the Helsinki timezone. Your options at this point are to use some 3rd party library (I recommend this), or hack-up the date object so you can use most of it's methods.
Option 1 - a 3rd party like moment-timezone
moment(1270544790922).tz('Europe/Helsinki').format('YYYY-MM-DD HH:mm:ss')
// outputs > 2010-04-06 12:06:30
moment(1270544790922).tz('Europe/Helsinki').hour()
// outputs > 12
This looks a lot more elegant than what we're about to do next.
Option 2 - Hack up the date object
var currentHelsinkiHoursOffset = 2; // sometimes it is 3
var date = new Date(1270544790922);
var helsenkiOffset = currentHelsinkiHoursOffset*60*60000;
var userOffset = _date.getTimezoneOffset()*60000; // [min*60000 = ms]
var helsenkiTime = new Date(date.getTime()+ helsenkiOffset + userOffset);
// Outputs > Tue Apr 06 2010 12:06:30 GMT-0700 (PDT)
It still thinks it's GMT-0700 (PDT), but if you don't stare too hard you may be able to mistake that for a date object that's useful for your purposes.
I conveniently skipped a part. You need to be able to define currentHelsinkiOffset. If you can use date.getTimezoneOffset() on the server side, or just use some if statements to describe when the time zone changes will occur, that should solve your problem.
Conclusion - I think especially for this purpose you should use a date library like moment-timezone.
To account for milliseconds and the user's time zone, use the following:
var _userOffset = _date.getTimezoneOffset()*60*1000; // user's offset time
var _centralOffset = 6*60*60*1000; // 6 for central time - use whatever you need
_date = new Date(_date.getTime() - _userOffset + _centralOffset); // redefine variable
Just another approach
function parseTimestamp(timestampStr) {
return new Date(new Date(timestampStr).getTime() + (new Date(timestampStr).getTimezoneOffset() * 60 * 1000));
};
//Sun Jan 01 2017 12:00:00
var timestamp = 1483272000000;
date = parseTimestamp(timestamp);
document.write(date);
Cheers!
I have a suspicion, that the Answer doesn't give the correct result. In the question the asker wants to convert timestamp from server to current time in Hellsinki disregarding current time zone of the user.
It's the fact that the user's timezone can be what ever so we cannot trust to it.
If eg. timestamp is 1270544790922 and we have a function:
var _date = new Date();
_date.setTime(1270544790922);
var _helsenkiOffset = 2*60*60;//maybe 3
var _userOffset = _date.getTimezoneOffset()*60*60;
var _helsenkiTime = new Date(_date.getTime()+_helsenkiOffset+_userOffset);
When a New Yorker visits the page, alert(_helsenkiTime) prints:
Tue Apr 06 2010 05:21:02 GMT-0400 (EDT)
And when a Finlander visits the page, alert(_helsenkiTime) prints:
Tue Apr 06 2010 11:55:50 GMT+0300 (EEST)
So the function is correct only if the page visitor has the target timezone (Europe/Helsinki) in his computer, but fails in nearly every other part of the world. And because the server timestamp is usually UNIX timestamp, which is by definition in UTC, the number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT), we cannot determine DST or non-DST from timestamp.
So the solution is to DISREGARD the current time zone of the user and implement some way to calculate UTC offset whether the date is in DST or not. Javascript has not native method to determine DST transition history of other timezone than the current timezone of user. We can achieve this most simply using server side script, because we have easy access to server's timezone database with the whole transition history of all timezones.
But if you have no access to the server's (or any other server's) timezone database AND the timestamp is in UTC, you can get the similar functionality by hard coding the DST rules in Javascript.
To cover dates in years 1998 - 2099 in Europe/Helsinki you can use the following function (jsfiddled):
function timestampToHellsinki(server_timestamp) {
function pad(num) {
num = num.toString();
if (num.length == 1) return "0" + num;
return num;
}
var _date = new Date();
_date.setTime(server_timestamp);
var _year = _date.getUTCFullYear();
// Return false, if DST rules have been different than nowadays:
if (_year<=1998 && _year>2099) return false;
// Calculate DST start day, it is the last sunday of March
var start_day = (31 - ((((5 * _year) / 4) + 4) % 7));
var SUMMER_start = new Date(Date.UTC(_year, 2, start_day, 1, 0, 0));
// Calculate DST end day, it is the last sunday of October
var end_day = (31 - ((((5 * _year) / 4) + 1) % 7))
var SUMMER_end = new Date(Date.UTC(_year, 9, end_day, 1, 0, 0));
// Check if the time is between SUMMER_start and SUMMER_end
// If the time is in summer, the offset is 2 hours
// else offset is 3 hours
var hellsinkiOffset = 2 * 60 * 60 * 1000;
if (_date > SUMMER_start && _date < SUMMER_end) hellsinkiOffset =
3 * 60 * 60 * 1000;
// Add server timestamp to midnight January 1, 1970
// Add Hellsinki offset to that
_date.setTime(server_timestamp + hellsinkiOffset);
var hellsinkiTime = pad(_date.getUTCDate()) + "." +
pad(_date.getUTCMonth()) + "." + _date.getUTCFullYear() +
" " + pad(_date.getUTCHours()) + ":" +
pad(_date.getUTCMinutes()) + ":" + pad(_date.getUTCSeconds());
return hellsinkiTime;
}
Examples of usage:
var server_timestamp = 1270544790922;
document.getElementById("time").innerHTML = "The timestamp " +
server_timestamp + " is in Hellsinki " +
timestampToHellsinki(server_timestamp);
server_timestamp = 1349841923 * 1000;
document.getElementById("time").innerHTML += "<br><br>The timestamp " +
server_timestamp + " is in Hellsinki " + timestampToHellsinki(server_timestamp);
var now = new Date();
server_timestamp = now.getTime();
document.getElementById("time").innerHTML += "<br><br>The timestamp is now " +
server_timestamp + " and the current local time in Hellsinki is " +
timestampToHellsinki(server_timestamp);​
And this print the following regardless of user timezone:
The timestamp 1270544790922 is in Hellsinki 06.03.2010 12:06:30
The timestamp 1349841923000 is in Hellsinki 10.09.2012 07:05:23
The timestamp is now 1349853751034 and the current local time in Hellsinki is 10.09.2012 10:22:31
Of course if you can return timestamp in a form that the offset (DST or non-DST one) is already added to timestamp on server, you don't have to calculate it clientside and you can simplify the function a lot. BUT remember to NOT use timezoneOffset(), because then you have to deal with user timezone and this is not the wanted behaviour.
Presuming you get the timestamp in Helsinki time, I would create a date object set to midnight January 1 1970 UTC (for disregarding the local timezone settings of the browser).
Then just add the needed number of milliseconds to it.
var _date = new Date( Date.UTC(1970, 0, 1, 0, 0, 0, 0) );
_date.setUTCMilliseconds(1270544790922);
alert(_date); //date shown shifted corresponding to local time settings
alert(_date.getUTCFullYear()); //the UTC year value
alert(_date.getUTCMonth()); //the UTC month value
alert(_date.getUTCDate()); //the UTC day of month value
alert(_date.getUTCHours()); //the UTC hour value
alert(_date.getUTCMinutes()); //the UTC minutes value
Watch out later, to always ask UTC values from the date object. This way users will see the same date values regardless of local settings.
Otherwise date values will be shifted corresponding to local time settings.
My solutions is to determine timezone adjustment the browser applies, and reverse it:
var timestamp = 1600913205; //retrieved from unix, that is why it is in seconds
//uncomment below line if you want to apply Pacific timezone
//timestamp += -25200;
//determine the timezone offset the browser applies to Date()
var offset = (new Date()).getTimezoneOffset() * 60;
//re-initialize the Date function to reverse the timezone adjustment
var date = new Date((timestamp + offset) * 1000);
//here continue using date functions.
This point the date will be timezone free and always UTC, You can apply your own offset to timestamp to produce any timezone.
Use this and always use UTC functions afterwards e.g. mydate.getUTCHours();
function getDateUTC(str) {
function getUTCDate(myDateStr){
if(myDateStr.length <= 10){
//const date = new Date(myDateStr); //is already assuming UTC, smart - but for browser compatibility we will add time string none the less
const date = new Date(myDateStr.trim() + 'T00:00:00Z');
return date;
}else{
throw "only date strings, not date time";
}
}
function getUTCDatetime(myDateStr){
if(myDateStr.length <= 10){
throw "only date TIME strings, not date only";
}else{
return new Date(myDateStr.trim() +'Z'); //this assumes no time zone is part of the date string. Z indicates UTC time zone
}
}
let rv = '';
if(str && str.length){
if(str.length <= 10){
rv = getUTCDate(str);
}else if(str.length > 10){
rv = getUTCDatetime(str);
}
}else{
rv = '';
}
return rv;
}
console.info(getDateUTC('2020-02-02').toUTCString());
var mydateee2 = getDateUTC('2020-02-02 02:02:02');
console.info(mydateee2.toUTCString());
// you are free to use all UTC functions on date e.g.
console.info(mydateee2.getUTCHours())
console.info('all is good now if you use UTC functions')

Categories

Resources