Rounding date by multiple weeks - javascript

It is easy to round dates to the start of the current week like so:
function roundWeek() {
var current = new Date();
var startOfWeek = current.getDate() - current.getDay();
console.log(new Date(current.setDate(startOfWeek)));
}
roundWeek();
This works fine when rounding by one week, but it gets a bit more complex when rounding by multiple weeks.
For instance, say I would like to round in three-week periods. I know this would require an epoch (such as new Date(0)) to be able to properly calculate the starting date of the three-week period, but this too causes an issue:
January 1, 1970 (which is new Date(0)) occured on a Thursday, so assuming I used it in the following manner, it would always calculate the start of the week to be on a Thursday:
function roundWeek(weeks) {
var current = new Date();
const WEEK_IN_MS = 60*60*24*7*1000; //sec * min * hr * day * ms
var index = Math.floor( (current.getTime() / (WEEK_IN_MS*weeks)) );
var startOfPeriod = new Date( index * WEEK_IN_MS*weeks );
console.log( startOfPeriod );
}
roundWeek(3);
How can this be modified so that it properly starts on a Sunday instead of a Thursday? Is there a better way of doing this? And most importantly: Would a leap year cause issues with this?

You need to decide whether you want the three-week period to start the Sunday before Jan 1, 1970 (12/28/69) or after. For example, which Sunday would Jan 14, 1970 round to? Then you can calculate the difference between Thursday and either the previous Sunday or next Sunday and add or subtract (depending on the decision you made) that to your rounded solution.
Here's a variation of you function that also takes a date as input for testing.
function roundWeek(weeks, d) {
var current = new Date(d);
var first_sunday = 60 * 60 * 24 * 4 * 1000 // seconds between Sunday and Thursday
const WEEK_IN_MS = 60 * 60 * 24 * 7 * 1000; // week in ms
var index = Math.floor((current.getTime() / (WEEK_IN_MS * weeks)));
console.log(`${weeks}-week periods from ${d.getMonth()+1}/${d.getDate()}/${d.getFullYear()} ${index}`)
var startOfPeriod = new Date(index * WEEK_IN_MS * weeks - first_sunday);
console.log("1st day of period:", startOfPeriod);
}
// round to three weeks starting Sunday before Jan 1 1970
roundWeek(3, new Date('January 2, 1970')); // Dec 28, 1968
roundWeek(3, new Date('January 14, 1970')); // Dec 28, 1968
roundWeek(3, new Date('January 22, 1970')); // next three weeks
roundWeek(3, new Date('May 16, 2018')); // since today. Sundaay May 6
Since leap years don't change how long a week is, they should be irrelevant.

Related

How to correctly calculate difference in days between 2 dates with DST change?

I have a task to get days difference between 2 dates. My solution is like here https://stackoverflow.com/a/543152/3917754 just I use Math.ceil instead of Math.round - cause 1 day and something is more than 1 day.
It was fine until I got dates between DST change. For example:
In my timezone DST change was on 30 Oct.
So when I'm trying to find days diff between dates 20 Oct and 10 Nov in result I get 23 instead of 22.
There are solution how to identify DST date but is it good solution to add/substract 1 day if date is/isn't dst?
function datediff(toDate, fromDate) {
const millisecondsPerDay = 1000 * 60 * 60 * 24; // milliseconds in day
fromDate.setHours(0, 0, 0, 0); // Start just after midnight
toDate.setHours(23, 59, 59, 999); // End just before midnight
const millisBetween = toDate.getTime() - fromDate.getTime();
var days = Math.ceil(millisBetween / millisecondsPerDay);
return days;
}
var startDate = new Date('2022-10-20');
var endDate = new Date('2022-11-10');
console.log('From date: ', startDate);
console.log('To date: ', endDate);
console.log(datediff(endDate, startDate));

Get the current week using JavaScript without additional libraries ? [SO examples are broken]

I built a calendar control and was adding the week numbers as a final touch, and encountered a problem with every script example I could find on SO and outside of SO (most of which one has copied from the other).
The issue is that when dates fall in partial months, the week calculation seems to mess up and either continue counting when it is the same week in a new month, or it thinks the last full week in a previous month is the same week number as the first full new week in the following month.
Following is a visual demonstration of one of the libraries (they all have their inaccuracies as they generally base their week calculation off a fixed number and build from there) :
You can view the codepen here as the project is rather complex, I have the Date.prototype.getWeek function at the start to play with this easier. Feel free to swap in any code from the samples found here on SO as they all end up funking out on some months.
Some of the calculations used :
Show week number with Javascript?
Date get week number for custom week start day
w3resource.com ISO86901
epoch calendar - getting ISO week
Get week of year in JavaScript like in PHP
When running the most current example (2017) from "Get week of year in JavaScript like in PHP", the week returned right now is 42. When you look on my calendar, the week in October right now is showing as 42 which is correct according to here https://www.epochconverter.com/weeks/2018.
Given the example, there are full weeks sharing the same week number - so I don't see how 42 can even be accurate.
Date.prototype.getWeek = function (dowOffset) {
/*getWeek() was developed by Nick Baicoianu at MeanFreePath: http://www.epoch-calendar.com */
dowOffset = typeof(dowOffset) == 'int' ? dowOffset : 0; //default dowOffset to zero
var newYear = new Date(this.getFullYear(),0,1);
var day = newYear.getDay() - dowOffset; //the day of week the year begins on
day = (day >= 0 ? day : day + 7);
var daynum = Math.floor((this.getTime() - newYear.getTime() -
(this.getTimezoneOffset()-newYear.getTimezoneOffset())*60000)/86400000) + 1;
var weeknum;
//if the year starts before the middle of a week
if(day < 4) {
weeknum = Math.floor((daynum+day-1)/7) + 1;
if(weeknum > 52) {
nYear = new Date(this.getFullYear() + 1,0,1);
nday = nYear.getDay() - dowOffset;
nday = nday >= 0 ? nday : nday + 7;
/*if the next year starts before the middle of
the week, it is week #1 of that year*/
weeknum = nday < 4 ? 1 : 53;
}
}
else {
weeknum = Math.floor((daynum+day-1)/7);
}
return weeknum;
};
Here is some code (also tried this) that is Sunday specific (see near the bottom). I am also pasting the relevant snip here :
/* For a given date, get the ISO week number
*
* Based on information at:
*
* http://www.merlyn.demon.co.uk/weekcalc.htm#WNR
*
* Algorithm is to find nearest thursday, it's year
* is the year of the week number. Then get weeks
* between that date and the first day of that year.
*
* Note that dates in one year can be weeks of previous
* or next year, overlap is up to 3 days.
*
* e.g. 2014/12/29 is Monday in week 1 of 2015
* 2012/1/1 is Sunday in week 52 of 2011
*/
function getWeekNumber(d) {
// Copy date so don't modify original
d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
// Set to nearest Thursday: current date + 4 - current day number
// Make Sunday's day number 7
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay()||7));
// Get first day of year
var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
// Calculate full weeks to nearest Thursday
var weekNo = Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7);
// Return array of year and week number
return [d.getUTCFullYear(), weekNo];
}
The algorithm is to use the week number of the following Saturday. So get the following Saturday, then use it's year for the 1st of Jan. If it's not a Sunday, go to the previous Sunday. Then get the number of weeks from there. It might sound a bit convoluted, but it's only a few lines of code. Most of the following is helpers for playing.
Hopefully the comments are sufficient, getWeekNumber returns an array of [year, weekNumber]. Tested against the Mac OS X Calendar, which seems to use the same week numbering. Please test thoroughly, particularly around daylight saving change over.
/* Get week number in year based on:
* - week starts on Sunday
* - week number and year is that of the next Saturday,
* or current date if it's Saturday
* 1st week of 2011 starts on Sunday 26 December, 2010
* 1st week of 2017 starts on Sunday 1 January, 2017
*
* Calculations use UTC to avoid daylight saving issues.
*
* #param {Date} date - date to get week number of
* #returns {number[]} year and week number
*/
function getWeekNumber(date) {
// Copy date as UTC to avoid DST
var d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
// Shift to the following Saturday to get the year
d.setUTCDate(d.getUTCDate() + 6 - d.getUTCDay());
// Get the first day of the year
var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
yearStart.setUTCDate(yearStart.getUTCDate() - yearStart.getUTCDay());
// Get difference between yearStart and d in milliseconds
// Reduce to whole weeks
return [d.getUTCFullYear(), (Math.ceil((d - yearStart) / 6.048e8))];
}
// Helper to format dates
function fDate(d) {
var opts = {weekday:'short',month:'short',day:'numeric',year:'numeric'};
return d.toLocaleString(undefined, opts);
}
// Parse yyyy-mm-dd as local
function pDate(s){
var b = (s+'').split(/\D/);
var d = new Date(b[0],b[1]-1,b[2]);
return d.getMonth() == b[1]-1? d : new Date(NaN);
}
// Handle button click
function doButtonClick(){
var d = pDate(document.getElementById('inp0').value);
var span = document.getElementById('weekNumber');
if (isNaN(d)) {
span.textContent = 'Invalid date';
} else {
let [y,w] = getWeekNumber(d);
span.textContent = `${fDate(d)} is in week ${w} of ${y}`;
}
}
Date:<input id="inp0" placeholder="yyyy-mm-dd">
<button type="button" onclick="doButtonClick()">Get week number</button><br>
<span id="weekNumber"></span>

How do I construct a javascript date using a 'day of the year (0 - 365)'? [duplicate]

I want to take a day of the year and convert to an actual date using the Date object. Example: day 257 of 1929, how can I go about doing this?
"I want to take a day of the year and convert to an actual date using the Date object."
After re-reading your question, it sounds like you have a year number, and an arbitrary day number (e.g. a number within 0..365 (or 366 for a leap year)), and you want to get a date from that.
For example:
dateFromDay(2010, 301); // "Thu Oct 28 2010", today ;)
dateFromDay(2010, 365); // "Fri Dec 31 2010"
If it's that, can be done easily:
function dateFromDay(year, day){
var date = new Date(year, 0); // initialize a date in `year-01-01`
return new Date(date.setDate(day)); // add the number of days
}
You could add also some validation, to ensure that the day number is withing the range of days in the year supplied.
The shortest possible way is to create a new date object with the given year, January as month and your day of the year as date:
const date = new Date(2017, 0, 365);
console.log(date.toLocaleDateString());
As for setDate the correct month gets calculated if the given date is larger than the month's length.
// You might need both parts of it-
Date.fromDayofYear= function(n, y){
if(!y) y= new Date().getFullYear();
var d= new Date(y, 0, 1);
return new Date(d.setMonth(0, n));
}
Date.prototype.dayofYear= function(){
var d= new Date(this.getFullYear(), 0, 0);
return Math.floor((this-d)/8.64e+7);
}
var d=new Date().dayofYear();
//
alert('day#'+d+' is '+Date.fromDayofYear(d).toLocaleDateString())
/* returned value: (String)
day#301 is Thursday, October 28, 2010
*/
Here is a function that takes a day number, and returns the date object
optionally, it takes a year in YYYY format for parameter 2. If you leave it off, it will default to current year.
var getDateFromDayNum = function(dayNum, year){
var date = new Date();
if(year){
date.setFullYear(year);
}
date.setMonth(0);
date.setDate(0);
var timeOfFirst = date.getTime(); // this is the time in milliseconds of 1/1/YYYY
var dayMilli = 1000 * 60 * 60 * 24;
var dayNumMilli = dayNum * dayMilli;
date.setTime(timeOfFirst + dayNumMilli);
return date;
}
OUTPUT
// OUTPUT OF DAY 232 of year 1995
var pastDate = getDateFromDayNum(232,1995)
console.log("PAST DATE: " , pastDate);
PAST DATE: Sun Aug 20 1995 09:47:18 GMT-0400 (EDT)
Here's my implementation, which supports fractional days. The concept is simple: get the unix timestamp of midnight on the first day of the year, then multiply the desired day by the number of milliseconds in a day.
/**
* Converts day of the year to a unix timestamp
* #param {Number} dayOfYear 1-365, with support for floats
* #param {Number} year (optional) 2 or 4 digit year representation. Defaults to
* current year.
* #return {Number} Unix timestamp (ms precision)
*/
function dayOfYearToTimestamp(dayOfYear, year) {
year = year || (new Date()).getFullYear();
var dayMS = 1000 * 60 * 60 * 24;
// Note the Z, forcing this to UTC time. Without this it would be a local time, which would have to be further adjusted to account for timezone.
var yearStart = new Date('1/1/' + year + ' 0:0:0 Z');
return yearStart + ((dayOfYear - 1) * dayMS);
}
// usage
// 2015-01-01T00:00:00.000Z
console.log(new Date(dayOfYearToTimestamp(1, 2015)));
// support for fractional day (for satellite TLE propagation, etc)
// 2015-06-29T12:19:03.437Z
console.log(new Date(dayOfYearToTimestamp(180.51323423, 2015)).toISOString);
If I understand your question correctly, you can do that from the Date constructor like this
new Date(year, month, day, hours, minutes, seconds, milliseconds)
All arguments as integers
You have a few options;
If you're using a standard format, you can do something like:
new Date(dateStr);
If you'd rather be safe about it, you could do:
var date, timestamp;
try {
timestamp = Date.parse(dateStr);
} catch(e) {}
if(timestamp)
date = new Date(timestamp);
or simply,
new Date(Date.parse(dateStr));
Or, if you have an arbitrary format, split the string/parse it into units, and do:
new Date(year, month - 1, day)
Example of the last:
var dateStr = '28/10/2010'; // uncommon US short date
var dateArr = dateStr.split('/');
var dateObj = new Date(dateArr[2], parseInt(dateArr[1]) - 1, dateArr[0]);
this also works ..
function to2(x) { return ("0"+x).slice(-2); }
function formatDate(d){
return d.getFullYear()+"-"+to2(d.getMonth()+1)+"-"+to2(d.getDate());
}
document.write(formatDate(new Date(2016,0,257)));
prints "2016-09-13"
which is correct as 2016 is a leaap year. (see calendars here: http://disc.sci.gsfc.nasa.gov/julian_calendar.html )
If you always want a UTC date:
function getDateFromDayOfYear (year, day) {
return new Date(Date.UTC(year, 0, day))
}
console.log(getDateFromDayOfYear(2020, 1)) // 2020-01-01T00:00:00.000Z
console.log(getDateFromDayOfYear(2020, 305)) // 2020-10-31T00:00:00.000Z
console.log(getDateFromDayOfYear(2020, 366)) // 2020-12-31T00:00:00.000Z

Invalid date issue using new Date()

I am passing timestamp to below function and it is returning me date string properly but when i am executing below line it is giving me error invalid date.
var postDate = new Date(this.ConvertServerDateToLocal(timestamp));
//postDate returns invalid date object.
ConvertServerDateToLocal: function(dateInput){
// EST - UTC offset: 4 hours
var offset = 4.0,
/*
- calculate the difference between the server EST date and UTC
- the value returned by the getTime method is the number of milliseconds since 1 January 1970 00:00:00 UTC.
- the time-zone offset is the difference, in minutes, between UTC and local time
- 60000 milliseconds = 60 seconds = 1 minute
*/
serverDate = new Date(dateInput),
utc = serverDate.getTime() - (serverDate.getTimezoneOffset() * 60000),
/*
- apply the offset between UTC and EST (4 hours)
- 3600000 milliseconds = 3600 seconds = 60 minutes = 1 hour
*/
clientDate = new Date(utc + (3600000 * offset));
return clientDate.toLocaleString();
}
Below is example timestamp i am passing to ConvertServerDateToLocal() function.
timestamp = "Nov 22, 2017 23:05:58" // Throwing invalid date after output
timestamp = "Nov 09, 2017 18:30:19" // Working properly
function ConvertServerDateToLocal(dateInput) {
// EST - UTC offset: 4 hours
dateInput = "Nov 09, 2017 18:30:19";
var offset = 4.0,
/*
- calculate the difference between the server EST date and UTC
- the value returned by the getTime method is the number of milliseconds since 1 January 1970 00:00:00 UTC.
- the time-zone offset is the difference, in minutes, between UTC and local time
- 60000 milliseconds = 60 seconds = 1 minute
*/
serverDate = new Date(dateInput.toString());
utc = serverDate.getTime() - (serverDate.getTimezoneOffset() * 60000);
/*
- apply the offset between UTC and EST (4 hours)
- 3600000 milliseconds = 3600 seconds = 60 minutes = 1 hour
*/
clientDate = new Date(utc + (3600000 * offset));
//return clientDate.toLocaleString();
alert(clientDate.toLocaleString());
}
Converting the input paramter to string worked for me. But I am not sure why one date worked and the other didn't work. If you found the answer, please post it here. I also use Dates a lot and they are always a pain.

MooTools: Get the first and last days of a given week

I'm relatively inexperienced in JavaScript (we're using MooTools, here) and I'm stuck with a problem:
Is there a quick way to get the first and last dates of a given week?
e.g. week 17 / 2015 starts on Monday, April 20th and ends on Sunday, April 26th.
My goal is to find out if a given week starts and ends in the same month (week 18 wont, since it starts on April 27th and ends on May 3rd).
Many thanks on any help with examples or pointing me to the right documentation.
I've been looking for a while and haven't found anything like this, and I find MooTools documentation very poor...
Boa noite Filipe,
to do this you do not need MooTools. You can do with Vanilla JS.
Here is an idea:
function dayAnalizer(str) {
var date = new Date(str).getTime();
var weekAfter = date + 7 * 24 * 60 * 60 * 1000;
return new Date(date).getMonth() == new Date(weekAfter).getMonth();
}
console.log(dayAnalizer('10-05-2015')); // true
console.log(dayAnalizer('13-05-2015')); // false
console.log(dayAnalizer('16-05-2015')); // false
jsFiddle: http://jsfiddle.net/1g4bvgjg/
basically it gets a date in string format and converts it to timestamp (miliseconds), then create another date 1 week forward. In the end compare if both have same month.
If you need to know if a certain week in a year starts and ends in the same month you could use something like this:
function weekAnalyser(week, year) {
var days = (1 + (week - 1) * 7); // 1st of January + 7 days for each week
var date = new Date(year, 0, days);
var dayOfWeek = date.getDay(); // get week day
var firstDayOfWeek = date.getTime() - (dayOfWeek) * 60 * 60 * 24 * 1000); // rewind to 1st day of week
var endOfWeek = firstDayOfWeek + 6 * 24 * 60 * 60 * 1000;
return new Date(firstDayOfWeek).getMonth() == new Date(endOfWeek).getMonth();
}
jsFiddle: http://jsfiddle.net/zfassz29/
Ps. Welcome to Portuguese Stackoverflow: https://pt.stackoverflow.com/

Categories

Resources