I'm trying to compute the age of an individual using D3.js.
I have the following code :
d3.timeYear.count(Birth_date, Current_date);
Birth_date being an individual's birth date (a Date object), and Current_date being, well, the date at which I'd like to compute the individual's age. To be able to answer "if you were born on May 5th, 1975, how old were you on May 3rd, 1976".
d3.timeYear.count() seems to floor the dates to the beginning of the year, so that in my example my code will return 1 on January 1st, 1976, even though the guy was 5 months away from his first birthday.
I could count the number of days instead of years, but I might get wrong results locally depending on the number of days in the year.
The following is based on the JavaScript Date object and should do the job:
function age(by,bm,bd){
const D=new Date(), y=D.getFullYear(),
md=D.getMonth()-bm, dd=D.getDate()-bd;
return y-by-(md>0||!md&&dd>=0?0:1);
}
console.log(age(1992,8,26))
Basically I return the difference between the full year of today and the birthday. But I also check, whether the current month is either greater than the birthday-month or (||) if the month-difference is zero (!md is true) and (&&) the day-difference dd is greater than zero. If that is the case I subtract 0 otherwise 1 from the year-difference.
And please be aware that my age() function expects the month to be entered in JavaScript notation. This means that 8 in the above example refers to the month of September.
The answer by Carsten Massman has inspired me to make this function, which solves my problem :
function age(birthdate, currentdate){
const bDay = birthdate.getDate(); // Get the birthdate's day.
const bMonth = birthdate.getMonth(); // Get the birthdate's month.
const currYear = currentdate.getFullYear(); // Get the current date's year.
const currBirthday = new Date(currYear + "/" + (bMonth + 1) + "/" + bDay); // Contruct the date of the birthday in the current year
const daysToBirthday = d3.timeDay.count( d3.timeYear.floor(currBirthday), currBirthday); // Count the # of days since Jan. 1st this year
// Offset the current date in the past by the number of days computed above.
const offsetCurrent = d3.timeDay.offset(currentdate, -daysToBirthday);
// Compute the number of years between the two dates (floored to the beginning of their respective year).
return d3.timeYear.count(birthdate, offsetCurrent);
}
This computes the age for any birth date, and at any point in time afterwards, using mostly d3-time and a little bit of vanilla javascript's Date methods.
Related
I am trying to get how many saturdays and sundays exist between two dates.
I get the first date from a input date field
<input value="" type="date" name="exit_end_document" id="exit_end_document" class="form-control" required>
My Javascript is this:
var fromDate = $('#exit_end_document').val();
I am getting the value.. the problem is that i do not know how can i calculate between that date which i get from input date field and today.
I have seen many examples but none of them do this...
(input date field) 2019-03-01 to (This date comes directly from JS) 2019-03-05 result = 2
Thanks!
Let's analyze this mathematically.
The starting date can either be on a Saturday or not. Likewise, the ending date can be either on a Saturday or not. In the simplest case, both dates are on Saturday; then you can see clearly that the number of Saturdays is equal to 1 plus the number of weeks between the two dates.
From there, it's easy to see that if the starting date is on a Saturday, but the ending date is not, then the number of Saturdays is equal to 1 plus the number of weeks between the two dates rounded down since the ending date's week has not reached Saturday yet. Turns out, that same math works for the first example, too, since you'll have an integer number of weeks between the dates. So we can cover both examples by simply using 1 + floor(weeks_between_dates) .
What if the ending date is a Saturday, but the starting date is not? Turns out, the math still works the same! This is the same as "moving back" the starting date from its Saturday, and that will add a partial week until it reaches the previous Saturday. Those partial weeks get rounded out by the floor, and once it reaches the previous Saturday, you'll be adding 1 anyway, as it'll be a full week added to the difference! So we're still good with 1 + floor(weeks_between_dates).
So the only possible combination left are two dates which are both not Saturday. This is the most complicated possibility. Let's start simple and assume the dates are two consecutive Wednesdays. Then they are 1 week apart and have 1 Saturday between them. Simple. If they're two weeks apart, they have 2 Saturdays. But what if it's a Wednesday and the following Tuesday? There is less than a week, but still 1 Saturday between them. And if it's a Wednesday and the following Thursday? More than 1 week, but still 1 Saturday! So in this case, we'd want to round the number of weeks up and stop there, giving us ceil(weeks_between_dates). But if they're both in the same week -- for instance, a Monday and a Friday in the same week -- then the answer is just 0. So how do we know whether the days are part of the same week? Assuming they're sorted and the start date is always before the ending date, then they're in the same week if and only if there is fewer than 1 week between them AND the starting weekday is before the ending weekday.
So the straight conditional logic here is this (in pseudocode):
weeks_between = floor((days between start and end) / 7)
if start.weekday = Saturday or end.weekday = Saturday, then:
return 1 + weeks_between
else if weeks_between = 0 and start.weekday is before end.weekday, then:
return 0
else
return ceil((days between start and end) / 7)
In order to handle leap years and timezones and whatnot, i suggest testing all the between days and testing them to see if they are sat or sunday:
var date1 = new Date("2012-06-04T05:00:00.000Z");
var date2 = new Date("2012-08-17T05:00:00.000Z");
var weekendDays = 0;
for(var i = +date1, mx = +date2; i<mx; i+=(1000*60*60*24)){
if({0:1,6:1}[new Date(i).getDay()]) weekendDays++;
}
alert(weekendDays); // 20
I already found the solution and it was given from #zak:
var fromDate = $('#exit_end_document').val();
fromDate = new Date(fromDate);
toDate = new Date();
var weekendDays = 0;
dayMilliseconds = 1000 * 60 * 60 * 24;
date1 = fromDate;
date2 = toDate;
while (date1 <= date2) {
var day = date1.getDay();
if (day == 0 || day == 6) {
weekendDays++;
}
date1 = new Date(+date1 + dayMilliseconds);
}
alert(weekendDays);
I need to get the weeks starting and ending date with Javascript/ moment.js
As input i have two values: year and week, which is the isoweek of moment.js
year = '2016'
week = '1'
should give me the 04.01.2016 and 10.01.2016
where the date has the german format moment().format('DD.MM.YYYY');
The solution from your comment will produce an incorrect result on 01.01.2017:
moment([2017,0,1]).year(2017).isoWeek(1).startOf('isoweek').format('DD.MM.YYYY');
// = '04.01.2016'
This one is more stable:
//var year = 2016;
//var week = 1;
var startDate = moment([year, 5, 30]).isoWeek(week).startOf('isoweek');
var endDate = moment(startDate).endOf('isoweek');
startDate.format('DD.MM.YYYY'); // = '04.01.2016'
endDate.format('DD.MM.YYYY'); // = '10.01.2016'
Explanation: if you initialize the moment instance with a date from week 53 of the previous year in conjunction with isoWeek or week, the year component of that moment instance is set to the previous year. All additional moment methods then operate on the "wrong" year.
Therefore use moment([year, 5, 30]) to initialize the moment instance. Any other day after the Jan 3rd works for 2016 too of course, only the few days that belong to week 53 of the previous year cause that problem.
moment([2016]).isoWeek(1).startOf('isoWeek').format('DD.MM.YYYY') // "02.01.2015"
I'm building a simple birthday reminder app where I get the names and birthdays in JSON and I need to display the names sorted based on whose birthday is coming next.
My logical thought would be to get the current day and month subtract that from the birthday and then do some kind of sort. But then how would do I handle -ve results or situations like when we are in Dec etc. I was guessing there might have been an simpler solution, but I'm quite clueless.
Here is a plunkr with the base working code: http://plnkr.co/edit/AkP6FRRG917TDdTtfWM7?p=preview
As others suggested, convert the string to a unix timestamp or date.
Here's an updated Plunker.
The controller adds a fromNow variable to the data:
$scope.friends.forEach(function(data){
var day = data.birthday.split("/")
var currentYear = new Date().getFullYear();
var birthdayDate = new Date(currentYear, day[0] - 1, day[1])
var now = new Date().valueOf();
if (birthdayDate.valueOf() < now){
birthdayDate.setFullYear(currentYear+1)
}
data.fromNow = birthdayDate.valueOf() - now;
})
Get the individual date/month parts (so we get a list like ["02","14","1985"])
Create a date object based on the current year, the month day[0] and the day day[1]. (Note we subtract 1 from the months because months are 0-based in in Javascript).
Get a numeric value for the current date/time
If the birthday is in the past add one year
Assign the number of milliseconds between now and the birthday to fromNow
You'd need to modify it so that if someone's birthday is today it doesn't add a year, thus placing it last in the list.
Also note I've added quotes to the orderBy parameter:
<tr ng-repeat="friend in friends| orderBy:'fromNow' ">
I would go about this by converting the dates to unix timestamps (int values) and doing a simple sort on them.
Convert date to timestamp using javascript Date.parse()
Convert the current date and birthdate to UNIX time and compare them based on the differences between these two values
birthdates = [new Date(1988,01,27), new Date(2013,01,01)];
birthdates.sort(function(firstDate,secondDate){
//calculate the difference between first date and current date
firstDifference = new Date() - firstDate;
//calculate difference between second date and current date.
secondDifference = new Date() - secondDate;
//return the smallest value.
return firstDifference - secondDifference;
});
//display the sorted array.
alert(birthdates);
if you look at my date validation when i come to test if it is in the past it works although the date constructor expects a zero date month so how do i subtract one from the substring value representing the month (one from the result, not the position)
//start of datefield
var dateformat=/^(?:(?:31\/(?:0[13578]|1[02])|(?:29|30)\/(?:0[13-9]|1[012])|(?:0[1-9]|1\d|2[0-8])\/(?:0[1-9]|1[0-2]))\/[2-9]\d{3}|29\/02\/(?:[2-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[3579][26])00))$/;
if (!date.match(dateformat))
{
errors.push("format incorrect use dd/mm/yyyy make sure you are entering correct days to the month remember 30 days have september, april, june & november, only 28 days in february unless leap year next is 2016");
}
var today = new Date();
var courseYear =date.substr(6,4) // use substr or substring to capture the last four digits
var courseMonth =date.substr(3,2) // use substr or substring to capture the four and fifth digits
var courseDay = date.substr(0,2)//e the first and second digits
var dateToCompare = new Date(courseYear, courseMonth, courseDay);
if (dateToCompare < today) {
errors.push("this date is in the past");
}
so how do i subtract one
With the subtraction operator "-" and the number literal "1". It also has the benefit of converting the string to a number before. For year and day, you might use the unary plus to do that conversion explicitly (though the Date constructor does it implicitly):
new Date(+courseYear, courseMonth-1, +courseDay);
I have been using Stack Overflow for a number of months now, but this is my first post.
I require a function to convert a week number and and day of week into a dd/mm/yyyy format.
The date values i have to work with are in the format day/weekNumber. So for example: 3/43 converts to Wednesday 24 October 20XX. The year value will be the current year.
The day value starts at 1 (Monday).
I have found lots of functions on the internet (such as this, this and this). Some work with ISO 8601 dates, which i do not think will work for me. And i have not yet found one that works for me.
Thanks in advance,
This solution does require an extra library to be added, but I think it is really worth it. It is a momentjs library for manipulating dates and time. It is actively maintained and has a great documentation. Once you get the values for day and weekNumber (in our case 3 and 43), you should do as follows:
function formatInput(day, weekNumber){
var currentDate = moment(new Date()); // initialize moment to a current date
currentDate.startOf('year'); // set to Jan 1 12:00:00.000 pm this year
currentDate.add('w',weekNumber - 1); // add number of weeks to the beginning of the year (-1 because we are now at the 1st week)
currentDate.day(day); // set the day to the specified day, Monday being 1, Sunday 7
alert(currentDate.format("dddd, MMMM Do YYYY")); // return the formatted date string
return currentDate.format("dddd, MMMM Do YYYY");
}
I think this library might be useful to you later on and there are plenty of possibilities regarding date and time manipulation, as well as formatting options. There is also a great documentation written for momentjs.
So assuming you have the values of 3 and 43 separately, you can just do some simple maths on the first day of the current year:
Get 1st January Current Year
Add (43 * 7 + 3)
Something like this maybe:
var currentDate = new Date();
var startOfYear = new Date(currentDate.getFullYear(), 0, 1);//note: months start at 0
var daysToAdd = (43 * 7) + 3;
//add days
startOfYear.setDate(startOfYear.getDate() + daysToAdd);
Here is an example
EDIT
On second thoughts, I think I was wrong with your requirements. It seems you require a specific day of the week. Check this out for a better solution.
The problem is that it all depends on your definition of a week. This year starts on a sunday, so does that mean that 02/01/2012 (the first monday of this year) is the start of the second week?
My latest example will first find the start of the specified week, and then find the next occurrence of the specified day
According to ISO when dealing with week dates, the week starts on Monday and the first week of the year is the one that contains the first Thursday of the year. So for 2012, the first week started on Monday, 2 January and the first week of 2013 will start on Monday, 31 December 2012.
So if 3/43 is the third day of the 43rd week (which is the ISO date 2012-W43-3), then it can be converted it to a date object using:
function customWeekDateToDate(s) {
var d, n;
var bits = s.split('/');
// Calculate Monday of first week of year this year
d = new Date();
d = new Date(d.getFullYear(),0,1); // 1 jan this year
n = d.getDay();
d.setDate(d.getDate() + (-1 * n +( n<5? 1 : 8)));
// Add days
d.setDate(d.getDate() + --bits[0] + --bits[1] * 7);
return d;
}
console.log(customWeekDateToDate('3/43')); // 01 2012-10-24
Note that this uses dates, otherwise daylight saving changeovers may result in the wrong date.