Display Date 1 Week Ago & Yesterdays Date - javascript

I'm trying to display 2 dates (local time), the exact date a week ago from today and the exact date yesterday with as little javascript as possible
Examples:
A week ago displayed as 10/07/14
and a day ago displayed as 10/12/14
I'm trying to display it in this way
<p>The date a week ago was <span id="weekago"></span></p>
<p>The date yesterday was <span id="yesterday"></span></p>

Though it would still take some javascript, you could do it like in this jsfiddle:
this helps to retract some days of the Date
Date.prototype.subtractDays = function(nrOfDays) {
var day = 1000 * 60 * 60 * 24;
return new Date(this - (day * nrOfDays));
}
this helps for the formatting (pad left)
Object.prototype.padLeft = function(char, nr) {
var s = this.toString();
while (s.length < nr) {
s = char + s;
}
return s;
};
this formats as you want it
Date.prototype.formatStandard = function() {
return (this.getMonth() + 1).padLeft('0', 2) + '/' +
(this.getDate()).padLeft('0', 2) + '/' +
this.getFullYear();
};
and this gets the elements containing a datefield (tag name would be datefield), and i opted to rather choose data-value as an attribute to choose which date to show (as you could have more than one weekago or yesterday field)
function encodeDateFields() {
var elems = document.getElementsByName('datefield'), i, len, item, value;
if (elems === null || !elems.length) {
alert('No fields found!');
return;
}
for (i = 0, len = elems.length; i < len; i++) {
item = elems[i];
value = item.getAttribute('data-value');
switch (value) {
case 'weekago':
item.innerHTML = new Date().subtractDays(7).formatStandard();
break;
case 'yesterday':
item.innerHTML = new Date().subtractDays(1).formatStandard();
break;
default:
item.innerHTML = value + ' wasn\'t found!';
}
}
}
and the function is called onDomReady (with jsfiddle)
encodeDateFields();
I made the following changes to your html
<p>The date a week ago was <span name="datefield" data-value="weekago"></span></p>
<p>The date yesterday was <span name="datefield" data-value="yesterday"></span></p>
You would need to code in any extra data-value attributes you might have, like now or tomorrow, but it should be quite obvious where you could do it :)

Related

Javascript: Tabbed time period charts

I'm trying to produce a graph like the following:
From an array of events as follows:
var events = {
"0": {"guid": "78926349827546", "created": "2017-07-07 14:14:21" },
"1": {"guid": "78926349827546", "created": "2017-07-08 15:44:10" },
"2": {"guid": "20936752065745", "created": "2017-07-09 12:09:24" },
"3": {"guid": "20936752065745", "created": "2017-07-11 06:55:42" },
"4": {"guid": "20936752065745", "created": "2017-07-11 22:10:29" },
...
};
I'm currently using the Google Line Chart. Although I'm happy with the aesthetic, I still need to find a way to produce a tabbed display of several timescales, e.g. Today, Last 7 Days, Last Month and Total.
Programmatically, this is proving to be a sisyphean task, as I have to count occurrences across (in one instance) every hour in the last day, and then (in another instance) every day in the last week etc.
And there's a lot of date conversion, counting backwards from today and so on.
Is there a way of taking my array and producing a new array of human-readable dates relative from today, across several timescales?
This is really a duplicate of a couple of questions like Where can I find documentation on formatting a date in JavaScript?, How to add months to a date in JavaScript? and Add days to JavaScript Date. So there are plenty of existing examples to work from.
Also, Google Charts has its own date formatter.
Anyway, you might use a function that takes a start date, end date and increment and returns an array of timestamps in a particular format. Formatting the strings can use a second function or the Google Charts formatter.
A bare bones version is very little code, to add some logic for forward or backward series takes a few more lines.
// Return date string in YYYY-MM-DD HH:mm:ss format
function formatDate(date) {
function z(n){return (n<10? '0':'') + n}
return date.getFullYear() + '-' +
z(date.getMonth() + 1) + '-' +
z(date.getDate()) + ' ' +
z(date.getHours()) + ':' +
z(date.getMinutes()) + ':' +
z(date.getSeconds());
}
// Return date strings from start date to end date
// with increment inc in hours
function getDateSeries(start, end, inc) {
var d = new Date(+start);
inc = +inc;
var dates = [];
// Deal with backwards sequences
var reverse = false, t;
if (start > end) {
t = start;
start = end;
end = t;
reverse = true;
}
if (inc < 0) {
reverse = true;
inc *= -1;
}
while (start <= end) {
dates.push(formatDate(start));
start.setHours(start.getHours() + inc);
}
return reverse? dates.reverse() : dates;
}
// Hourly intervals over 2 days forwards
console.log(getDateSeries(new Date(2017,7,18), new Date(2017,7,19), 1));
// 6 hourly intervals over 10 days backwards
console.log(getDateSeries(new Date(2017,7,28), new Date(2017,7,18), -6));
// Hourly intervals from now going back 24 hours
var now = new Date();
var end = new Date(+now);
end.setDate(end.getDate() - 1);
console.log(getDateSeries(now, end, -1))
// Daily intervals from today going back 30 days
var now = new Date();
now.setHours(0,0,0,0);
var end = new Date(+now);
end.setDate(end.getDate() - 30);
console.log(getDateSeries(now, end, -24))
There are plenty of libraries around to help with formatting, incrementing and decrementing dates but if this is all you want to do, it doesn't take much to write.
This could be modified so the start is always "now" or "today" and use an interval in days rather than a start and end date with hours.
Where a library would come in handy is if you want say monthly intervals on the last day of the month or similar (since months aren't of equal length). So using moment.js you could do:
function getMonthlySequenceStart(months) {
var format = 'YYYY-MM-DD HH:mm:ss'
var now = moment().startOf('month');
var count = Math.abs(months);
var direction = months < 0? -1 : 1;
var result = [];
while (count--) {
result.push(now.format(format));
now.add(direction, 'months');
}
return result;
}
console.log(getMonthlySequenceStart(-12));
function getMonthlySequenceEnd(months) {
var format = 'YYYY-MM-DD HH:mm:ss'
var now = moment().endOf('month').startOf('day');
var count = Math.abs(months);
var direction = months < 0? -1 : 1;
var result = [];
while (count--) {
result.push(now.format(format));
now.add(direction, 'months');
now.endOf('month').startOf('day');
}
return result;
}
console.log(getMonthlySequenceEnd(-12));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
Not using a library isn't too hard either. The following sets the date to the first of the month as then it's easy to decrement by 1 month, then get the day before (the last day of the previous month) for the string:
// Sequence of end of months from current month
// back for num months
function getMonthlySequenceEnd(num) {
var now = new Date();
now.setHours(0,0,0,0);
var t, result = [];
// Set to first day of next month
now.setMonth(now.getMonth() + 1, 1)
while (num--) {
t = new Date(+now);
t.setDate(t.getDate() - 1);
result.push(formatDate(t));
now.setMonth(now.getMonth() - 1);
}
return result;
}
function formatDate(date) {
function z(n) {return (n < 10 ? '0' : '') + n}
return date.getFullYear() + '-' + z(date.getMonth() + 1) + '-' + z(date.getDate()) + ' ' +
z(date.getHours()) + ':' + z(date.getMinutes()) + ':' + z(date.getSeconds());
}
console.log(getMonthlySequenceEnd(24));
So I think you now have enough to do whatever is required.

Why does does removing a line effect the next one?

I'm attempting to return different days based on a given date, such as the first Monday of the week, the Friday of the week, as well as days in previous and following weeks so that I can figure out the start and end of my pay periods (for my two jobs, each are different) as well as the pay date for that period.
When I remove the Logger.log("Prev Monday > " + addDays(pMonday, -7));
the next line's value changes. What is removed line doing to mess up the following one?
I'm using this in Google App Scripts so I can pull data from a Google Calendar to a Google Sheet easily. It also means no extra libraries.
function test_monday(){
var theDate = new Date();
theDate.setDate(16);
theDate.setMonth(5);
theDate.setFullYear(2016);
theDate.setHours(12,0,0,0)
Logger.log(theDate);
var pMonday = new Date();
pMonday = getMonday( theDate ) ;
Logger.log("pMonday: " + pMonday)
Logger.log("Prev Monday > " + addDays(pMonday, -7));
Logger.log("Following Friday > " + addDays(pMonday, 4));
}
function getMonday( date ) {
var day = date.getDay() || 7;
if( day !== 1 )
date.setHours(-24 * (day - 1));
return date;
}
function addDays(d, n){
var date = new Date();
date = d;
var offset = n;
date.setHours(24 * ( offset ));
return date;
}
date = d;
This line right here completely undoes the work you did in the previous line. It says that date is the exact same instance as d. That means that whenever you modify date (date.setHours(24 * offset)) you're also modifying d. You might as well be writing d.setHours(24 * offset) because they mean the same thing.
If you want to create a new Date object equal to another one, just pass the original into the Date constructor. So you could rewrite your function as:
function addDays(d, n) {
var date = new Date(d);
date.setHours(24 * n);
return date;
}

Working Days Javascript with Extra Dates

I have a function which calculates a date that is passed and adds a given number of days to the result ensuring the outputted date doesn't fall on a weekend.
The function
function addWorkingDays(datStartDate, lngNumberOfWorkingDays, blnIncSat, blnIncSun) {
var intWorkingDays = 5;
var intNonWorkingDays = 2;
var intStartDay = datStartDate.getDay(); // 0=Sunday ... 6=Saturday
var intOffset;
var intModifier = 0;
if (blnIncSat) { intWorkingDays++; intNonWorkingDays--; }
if (blnIncSun) { intWorkingDays++; intNonWorkingDays--; }
var newDate = new Date(datStartDate)
if (lngNumberOfWorkingDays >= 0) {
// Moving Forward
if (!blnIncSat && blnIncSun) {
intOffset = intStartDay;
} else {
intOffset = intStartDay - 1;
}
// Special start Saturday rule for 5 day week
if (intStartDay == 6 && !blnIncSat && !blnIncSun) {
intOffset -= 6;
intModifier = 1;
}
} else {
// Moving Backward
if (blnIncSat && !blnIncSun) {
intOffset = intStartDay - 6;
} else {
intOffset = intStartDay - 5;
}
// Special start Sunday rule for 5 day week
if (intStartDay === 0 && !blnIncSat && !blnIncSun) {
intOffset++;
intModifier = 1;
}
}
// ~~ is used to achieve integer division for both positive and negative numbers
newDate.setDate(datStartDate.getDate() + new Number((~~((lngNumberOfWorkingDays + intOffset) / intWorkingDays) * intNonWorkingDays) + lngNumberOfWorkingDays + intModifier));
return newDate;
}
I need to now add some dates to this function for it to take into account, these are public holiday's in Sydney Australia. What I am looking to achieve is the following.
var newDate = addWorkingDays('30/09/2015', 3, false, false);
In this example the returned date would fall on the 03/10/2015 which is a public holiday and therefore we would need to return the 04/10/2015
The dates in question are:
01/01/2015 New Year's Day
26/01/2015 Australia Day
09/03/2015 Labour Day / Eight Hours Day / Adelaide Cup / Canberra Day
03/04/2015 Good Friday
06/04/2015 Easter Monday
25/04/2015 ANZAC Day
08/06/2015 Queen's Birthday
03/08/2015 Bank Holiday / Picnic Day
05/10/2015 Labour Day
03/11/2015 Melbourne Cup
25/12/2015 Christmas Day
26/12/2015 Boxing Day
Given the function above can someone help me to amend the function to take these dates into account.
As it is your code gives me errors when I try to call it like you specify, but regardless you should simply be able to check if the date you're going to give as an answer is one of your invalid dates, and if so then return the next working day:
(pseudocode)
newDate.setDate(datStartDate.getDate() + new Number((~~((lngNumberOfWorkingDays + intOffset) / intWorkingDays) * intNonWorkingDays) + lngNumberOfWorkingDays + intModifier));
if (newDate == "01/01/2015" || newDate == "26/01/2015" || ....) {
return addWorkingDays(newDate, 1, blnIncSat, blnIncSun);
}
else {
return newDate;
}

previous quarters in javascript

Forgive me I tried several searches here and other places in general but cant seem to fix issue I am having at the moment. Can someone please help me figure out?
I am trying to find quarter strings from inputdate in JavaScript. For "01/31/2009" it should give Q1,2013 Q4,2012 etc based on offset given as input parameter. when offset is 0 then current quarter, 1 then previous, 2 then previous 2 quarter etc...
my current code: jsfiddle
function getQuarterStrings(id) {
var d = new Date();
var d = new Date("01/31/2009");
var str;
switch (id) {
...
}
Remaining code is in jsfiddle. As you can see, it fails on second last condition even though everything seems ok. Please help me figure out my mistake. Thank you!
Some of your comparisons are off, and Date tries to compensate for months that don't have as many days when you setMonth. This code should work:
function getQuarterStrings(id) {
var d = new Date("03/31/2009");
d.setDate(1);
d.setMonth(d.getMonth() - id * 3);
var month = d.getMonth() + 1;
var year = d.getFullYear();
var quarter = Math.ceil(month / 3);
return ("Q" + quarter + ", " + year);
}
This works, and is a lot more concise. It also allows you to use any offset instead of a limited set of values:
function getQuarterStrings(date, id) {
// quarter is 0-based here
var quarter = Math.floor(date.getMonth() / 3),
year = date.getFullYear();
quarter -= id;
if(quarter < 0) {
var yearsChanged = Math.ceil(-quarter / 4);
year -= yearsChanged;
// Shift quarter back to a nonnegative number
quarter += 4 * yearsChanged;
}
return "Q" + (quarter + 1) + ", " + year;
}
http://jsfiddle.net/dPmf2/6/
You can also get rid of the switch statement by doing this:
function getQuarterStrings(id) {
var d = new Date();
var d = new Date("01/31/2009");
var str;
if (id !== 0){
d.setMonth(d.getMonth() - 3*id);
}
str = getQuarter(d);
return str;
}

Calculate an expected delivery date (accounting for holidays) in business days using JavaScript?

After revisiting this script, and some modifications, the following is available to allow a user to add a feature that calculates the expected delivery date.
// array of ISO YYYY-MM-DD format dates
publicHolidays = {
uk:["2020-01-01","2020-04-10","2020-04-13","2020-05-08","2020-05-25",
"2020-08-03","2020-08-31","2020-12-25","2020-12-28"],
usa:["2020-01-01","2020-01-20","2020-02-14","2020-02-17","2020-04-10",
"2020-04-12","2020-05-10","2020-05-25","2020-06-21","2020-07-03",
"2020-07-04","2020-09-07","2020-10-12","2020-10-31","2020,11,11",
"2020-11-26","2020-12-25"]
}
// check if there is a match in the array
Date.prototype.isPublicHoliday = function( data ){// we check for a public holiday
if(!data) return 1;
return data.indexOf(this.toISOString().slice(0,10))>-1? 0:1;
}
// calculation of business days
Date.prototype.businessDays = function( d, holidays ){
var holidays = holidays || false, t = new Date( this ); // copy date.
while( d ){ // we loop while d is not zero...
t.setDate( t.getDate() + 1 ); // set a date and test it
switch( t.getDay() ){ // switch is used to allow easier addition of other days of the week
case 0: case 6: break;// sunday & saturday
default: // check if we are a public holiday or not
d -= t.isPublicHoliday( holidays );
}
}
return t.toISOString().slice(0,10); // just the YYY-MM-DD
}
// dummy var, could be a form field input
OrderDate = "2020-02-12";
// test with a UK holiday date
var deliveryDate = new Date(OrderDate).businessDays(7, publicHolidays.usa);
// expected output 2020-02-25
console.log("Order date: %s, Delivery date: %s",OrderDate,deliveryDate );
Order date: 2020-02-12, Delivery date: 2020-02-25
The prototype is written to allow inputs from forms (HTML5 forms) of date type inputs as they are already in an ISO YYYY-MM-DD format and the output is formatted as such should that be needing to update a particular field.
The typical use would be...
var delDate = new Date( ISOdate ).businessDays( addBusinessDays, holidayData );
where the delDate is an ISO format date, eg, 2020-01-01
I've adapted Mark Giblin's revised code to better deal with end of year dates and also U.S. federal holidays. See below...
function businessDaysFromDate(date,businessDays) {
var counter = 0, tmp = new Date(date);
while( businessDays>=0 ) {
tmp.setTime( date.getTime() + counter * 86400000 );
if(isBusinessDay (tmp)) {
--businessDays;
}
++counter;
}
return tmp;
}
function isBusinessDay (date) {
var dayOfWeek = date.getDay();
if(dayOfWeek === 0 || dayOfWeek === 6) {
// Weekend
return false;
}
holidays = [
'12/31+5', // New Year's Day on a saturday celebrated on previous friday
'1/1', // New Year's Day
'1/2+1', // New Year's Day on a sunday celebrated on next monday
'1-3/1', // Birthday of Martin Luther King, third Monday in January
'2-3/1', // Washington's Birthday, third Monday in February
'5~1/1', // Memorial Day, last Monday in May
'7/3+5', // Independence Day
'7/4', // Independence Day
'7/5+1', // Independence Day
'9-1/1', // Labor Day, first Monday in September
'10-2/1', // Columbus Day, second Monday in October
'11/10+5', // Veterans Day
'11/11', // Veterans Day
'11/12+1', // Veterans Day
'11-4/4', // Thanksgiving Day, fourth Thursday in November
'12/24+5', // Christmas Day
'12/25', // Christmas Day
'12/26+1', // Christmas Day
];
var dayOfMonth = date.getDate(),
month = date.getMonth() + 1,
monthDay = month + '/' + dayOfMonth;
if(holidays.indexOf(monthDay)>-1){
return false;
}
var monthDayDay = monthDay + '+' + dayOfWeek;
if(holidays.indexOf(monthDayDay)>-1){
return false;
}
var weekOfMonth = Math.floor((dayOfMonth - 1) / 7) + 1,
monthWeekDay = month + '-' + weekOfMonth + '/' + dayOfWeek;
if(holidays.indexOf(monthWeekDay)>-1){
return false;
}
var lastDayOfMonth = new Date(date);
lastDayOfMonth.setMonth(lastDayOfMonth.getMonth() + 1);
lastDayOfMonth.setDate(0);
var negWeekOfMonth = Math.floor((lastDayOfMonth.getDate() - dayOfMonth - 1) / 7) + 1,
monthNegWeekDay = month + '~' + negWeekOfMonth + '/' + dayOfWeek;
if(holidays.indexOf(monthNegWeekDay)>-1){
return false;
}
return true;
}
Thanks for your input guys, I had a long hard re-think over the approach I was making for this and came up with this little number...
var businessDays = 7, counter = 0; // set to 1 to count from next business day
while( businessDays>0 ){
var tmp = new Date();
var startDate = new Date();
tmp.setDate( startDate .getDate() + counter++ );
switch( tmp.getDay() ){
case 0: case 6: break;// sunday & saturday
default:
businessDays--;
};
}
The idea was to start with the business days and count backwards to zero for each day encountered that fell in to the range of a business day. This use of switch would enable a person to declare a day in the week as a non-business day, for example someone may not work on a monday, therefore the addition of case:1 would include a monday.
This is a simple script and does not take in to account public or bank holidays, that would be asking for a much more complex script to work with.
The result is a date that is set to the date of shipping, the user can then extract the date info in any format that they please, eg.
var shipDate = tmp.toUTCString().slice(1,15);
We have UI that defaults search inputs to last business day or a week-ago.
Here's something that works both forward and backward.
// add (or subtract) business days to provided date
addBusinessDays = function (startingDate, daysToAdjust) {
var newDate = new Date(startingDate.valueOf()),
businessDaysLeft,
isWeekend,
direction;
// Timezones are scary, let's work with whole-days only
if (daysToAdjust !== parseInt(daysToAdjust, 10)) {
throw new TypeError('addBusinessDays can only adjust by whole days');
}
// short-circuit no work; make direction assignment simpler
if (daysToAdjust === 0) {
return startingDate;
}
direction = daysToAdjust > 0 ? 1 : -1;
// Move the date in the correct direction
// but only count business days toward movement
businessDaysLeft = Math.abs(daysToAdjust);
while (businessDaysLeft) {
newDate.setDate(newDate.getDate() + direction);
isWeekend = newDate.getDay() in {0: 'Sunday', 6: 'Saturday'};
if (!isWeekend) {
businessDaysLeft--;
}
}
return newDate;
};
It would be easy to pass in an optional holidays data structure and adjust for that as well.
However, generating a holidays data structure, well, that will take a little more effort and is specific not only to every country and region, but also to every organization.
Your main problem was that adding safety each time meant you were adding multiple days each time it looped, instead of 1. So first loop = 1, second = 1+2, etc.
I believe this works as you'd like:
var businessDays = 10; // this will come from a form
var counter = 0; // I have a counter
var safety = 0; // I have a safety variable
var ship = today = new Date(); // I have the current date and an initialized shipping variable but the buy date will come from a form
console.log(">>> today = " + today);
// now the loop...
while( ++safety <30 ){
ship.setDate(ship.getDate()+1 );
switch( ship.getDay() ){
case 0: // Sunday
case 6: // Saturday
break;
default:
counter++;
}
if( counter >= businessDays ) break;
}
// add a number of days
// the expected shipping date
console.log(">>> days = " + businessDays);
console.log(">>> ship = " + ship);
Change line 7 from
ship.setDate( safety ); // add a number of days
to
ship.setDate( ship.getDate() + safety );
The problem was that you want to add days, not set days.
I needed something similar but a little different and this is what I came up with.
Holidays are added in an object with one key for each month that has holidays. That key then has an array of days in that month that are considered holidays.
function getDueDate(date) {
var numBusinessDays = 20;
var saturday = 6;
var sunday = 0;
var holidays = {
/* Months are zero-based. 0 = Jan, 11 = Dec */
0: [1, 2],
1: [6],
3: [24],
11: [25, 26]
};
var dayOfWeek = null;
var dayOfMonth = null;
var month = null;
var isWeekday = null;
var monthHolidays = null;
var isHoliday = null;
while (numBusinessDays > 0) {
dayOfWeek = date.getDay();
dayOfMonth = date.getDate();
month = date.getMonth();
isWeekday = dayOfWeek !== saturday && dayOfWeek !== sunday;
monthHolidays = holidays[month];
isHoliday = monthHolidays
? monthHolidays.indexOf(dayOfMonth) > -1
: false;
if (isWeekday && !isHoliday) --numBusinessDays;
date.setDate(dayOfMonth + 1);
}
return date;
}
ship.setDate( safety ); // add a number of days
Doesn't add days. It sets the day.
More info
The setDate() method sets the day of the Date object relative to the beginning of the currently set month.
If you want to add days do something like this:
ship.setDate(ship.getDate()+1);
I just found this script which is working nice, you can give an optional array for your country's holidays
function addBusinessDays(date, days, holidays) {
var calendar = java.util.Calendar.getInstance();
calendar.setTimeInMillis(date.getTime());
var numberOfDaysToAdd = Math.abs(days);
var daysToAdd = days < 0 ? -1 : 1;
var businessDaysAdded = 0;
function isHoliday(dateToCheck) {
if (holidays && holidays.length > 0) {
for (var i = 0; i < holidays.length; i++) {
if (holidays[i].getFullYear() == dateToCheck.get(java.util.Calendar.YEAR) && holidays[i].getMonth() == dateToCheck.get(java.util.Calendar.MONTH) && holidays[i].getDate() == dateToCheck.get(java.util.Calendar.DAY_OF_MONTH)) {
return true;
}
}
}
return false;
}
while (businessDaysAdded < numberOfDaysToAdd) {
calendar.add(java.util.Calendar.DATE, daysToAdd);
if (calendar.get(java.util.Calendar.DAY_OF_WEEK) == java.util.Calendar.SATURDAY || calendar.get(java.util.Calendar.DAY_OF_WEEK) == java.util.Calendar.SUNDAY) {
// add another day
continue;
}
if (isHoliday(calendar)) {
// add another day
continue;
}
businessDaysAdded ++;
}
return new Date(calendar.getTimeInMillis());
}

Categories

Resources