I want to make a list of last months dates in cell A5:A35.
I am currently just using formulas but it is going to list all the days regardless of count in the month. So when I make the sheet for November, it's going to have December 1st on the list. I don't want that.
I tried scripting to get the current month and searching the range for that month but it's not working and seems convoluted. There must be a cleaner way.
I just want to programmatically list the days in the prior month.
I have this
Code function won't work on mobile
function assignDates() {
const cell = sheet.getRange('A5:A35');
cell.setFormula(=EOMONTH(TODAY(),-2)+D5
d5 is a hidden column with 1,2,3... etc. It's a really cheap way to do it.
It will list 31 days regardless of the length of the month.
Now to deal with this, I tried to make a script to get the current month and then delete entries that contain that but it does not work.
//check to see if dates fall within month
function dateCheck(sheet){
var sheet = SpreadsheetApp.getActive().getSheetByName('test');
//get current month
var month = Utilities.formatDate(new Date(), "GMT-5", "MMMM")
// Delete days that fall out of range
var dayRange = sheet.getRange('A5:A36').getDisplayValues();
dayRange.forEach((date) => { if (date.toString().includes(month))
{ sheet.getRangeList(dayRange).clearContent() } })
}
=SEQUENCE(DAYS(EOMONTH(TODAY(),)+1,EOMONTH(TODAY(),-1)+1),1,EOMONTH(TODAY(),-1)+1)
DAYS to calculate number of days in this month
EOMONTH to get end date of last month and this month
SEQUENCE to create sequence of dates.
You need to change TODAY() to a static date string, if you don't want the sequence to change every month.
Get Last Month and This Month Calendar on a Spreadsheet
Code:
function getCalendar() {
const ss = SpreadsheetApp.getActive()
const sh = ss.getActiveSheet();
sh.clear();
let oA = [];
oA.push(monthlyCalendar(new Date().getMonth() - 1, null, true));//helper function
oA.push(monthlyCalendar(new Date().getMonth(), null, true));//helper function
//oA.push(monthlyCalendar(new Date().getMonth() + 1, null, true));
oA.forEach((obj, i) => {
if (i == 0) {
sh.getRange(1, 1, 2, obj.cA[0].length).setFontWeight('bold');
sh.getRange(1, 1, obj.cA.length, obj.cA[0].length).setValues(obj.cA);
} else {
let sr = sh.getLastRow() + 2;
sh.getRange(sr, 1, 2, obj.cA[0].length).setFontWeight('bold');
sh.getRange(sr, 1, obj.cA.length, obj.cA[0].length).setValues(obj.cA);
if (obj.roff && obj.coff) {
sh.getRange(sr, 1).offset(obj.roff, obj.coff).setFontWeight('bold').setFontColor('red');//sets the current date to bold and red
}
}
});
}
Helper Function:
function monthlyCalendar(m, wsd, ret) {
var m = m || new Date().getMonth();
var wsd = wsd || 1;//defaults to Monday
var ret = ret || false;
const td = new Date();
const [cy,cm,cd] = [td.getFullYear(),td.getMonth(),td.getDate()];
const dA = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const oA = [...Array.from(Array(7).keys(), idx => dA[(idx + wsd) % 7])]
let dObj = {};
let midx = {};
let rObj = {cA:null,roff:null,coff:null};
oA.forEach(function (e, i) { dObj[e] = i; });
const mA = [...Array.from(new Array(12).keys(), x => Utilities.formatDate(new Date(2021, x, 15), Session.getScriptTimeZone(), "MMM"))];
mA.forEach((e, i) => { midx[i] = i; })
let cA = [];
let bA = [];
let wA = [null, null, null, null, null, null, null];
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
sh.clear();
const year = new Date().getFullYear();
let i = midx[m % 12];
let month = new Date(year, i, 1).getMonth();
let dates = new Date(year, i + 1, 0).getDate();
cA.push([mA[month], dates, '', '', '', '', '']);
bA.push(['#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff']);
cA.push(oA)
//bA.push(['#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00']);
let d = [];
let ddd = [];
for (let j = 0; j < dates; j++) {
let day = new Date(year, i, j + 1).getDay();
let date = new Date(year, i, j + 1).getDate();
if (day < wA.length) {
wA[dObj[dA[day]]] = date;
}
if(cy == year && cm == month && cd == date) {
rObj.roff = cA.length;
rObj.coff = dObj[dA[day]];
}
if (dA[day] == oA[wA.length - 1] || date == dates) {
cA.push(wA);
//bA.push(['#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff']);
wA = ['', '', '', '', '', '', ''];
}
}
if (!ret) {
rObj.cA = cA;
sh.getRange(1, 1, rObj.cA.length, rObj.cA[0].length).setValues(cA);
if (rObj.roff && rObj.coff) {
sh.getRange(1, 1).offset(rObj.roff, rObj.coff).setFontWeight('bold').setFontColor('red');
}
} else {
rObj.cA = cA;
return rObj;
}
}
Demo:
Nice challenge!
Enter the following function on A5:
=arrayformula(if(eomonth(today(),-2)+row(A5:A35)+1-row()>eomonth(today(),-1),"",eomonth(today(),-2)+row(A5:A35)+1-row()))
It will retrieve all dates from the 1st until the last date of the last month (related to today()). until 31th, 30th, 28th, or 29th dynamically!
Cheers!
If you need a script here you go:
function myFunction() {
var today = new Date();
var year = today.getFullYear();
var month = today.getMonth(); // 0 -> January, 1 -> February, etc...
// get the number of days of the previous month
// 'zero day' of a month is the last day of a previous month
var len = new Date(year, month, 0).getDate();
// make an array with dates (strings, actually)
var options = { year: 'numeric', month: 'numeric', day: 'numeric' };
var dates = new Array(len).fill('').map((_, day) =>
[new Date(year, month-1, day+1).toLocaleString('en-US', options)])
// put the array on the sheet
SpreadsheetApp.getActiveSheet().getRange(5,1,len,1).setValues(dates);
}
Dates is a tricky thing always.
Related
I am trying to get a list of months between two dates in Dart
Example :
Input Date:
date 1 - 20/12/2011
date 2 - 22/08/2012
Now, my expected result should be :
12/2011
1/2012
2/2012
3/2012
4/2012
5/2012
6/2012
7/2012
8/2012
Thanks for your help!
You can do this:
var date1 = DateFormat("dd/MM/yyyy").parse("20/12/2021");
var date2 = DateFormat("dd/MM/yyyy").parse("22/08/2022");
while (date1.isBefore(date2)) {
print(DateFormat("M/yyyy").format(date1));
date1 = DateTime(date1.year, date1.month + 1);
}
You need
import 'package:intl/intl.dart';
Not exactly what OP has asked for, but I wanted to share this solution which takes me a while.
This solution also considers the day, and handle correctly the case for February 28.
static List<DateTime> extractMonthsInRange(DateTime from, DateTime to) {
//0. save day of from date
var daysInFromDate = from.day;
List<DateTime> monthsInRange = [DateTime(from.year, from.month)];
//1. get a list of months between 2 dates (without days)
while (from.isBefore(DateTime(to.year, to.month - 1))) {
var newFrom = DateTime(from.year, from.month + 1);
monthsInRange.add(newFrom);
from = newFrom;
}
//2. iterate months
return monthsInRange.map((month) {
var _lastDayOfMonth = lastDayOfMonth(month);
//2. if the day of the from date is < then the day of the last day of the month using the daysInFromDate
if (daysInFromDate < _lastDayOfMonth.day) {
return DateTime(month.year, month.month, daysInFromDate);
}
//3. else save the last day of the month (means that the month has less days)
return _lastDayOfMonth;
}).toList();
}
/// The last day of a given month
static DateTime lastDayOfMonth(DateTime month) {
var beginningNextMonth = (month.month < 12)
? DateTime(month.year, month.month + 1, 1)
: DateTime(month.year + 1, 1, 1);
return beginningNextMonth.subtract(Duration(days: 1));
}
Please feel free to improve my code in the comments.
you can use
date1.subtract(Duration(days: 7, hours: 3, minutes: 43, seconds: 56));
date1.add(Duration(days: 1, hours: 23)));
to add oder subtract days, months ...or what u like.... then do a if check in a loop or a while loop
something like this:
void main() {
DateTime a = DateTime.now();
DateTime b = a.add(Duration(days: 360));
DateTime c = a;
while (c.millisecondsSinceEpoch<b.millisecondsSinceEpoch)
{
c = c.add(Duration(days:31));
print('${c.month}/${c.year}');
}
}
Hi i want to compare column with date (i.e "Referral Date" column)
with present day , here is what i have
function newF(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Worksheet');
var range = ss.getDataRange();
var headers = range.getValues()[0];
var colIndex = headers.indexOf("Referral Date");
var today = new Date();
var searchRange = ss.getRange(2,colIndex+1,ss.getLastRow()-1);
for (i=0;i<range.getLastRow();i++){
var dates = searchRange.getValues();
if (today.valueOf()>dates.valueOf()){
updatelFilter()
} else{
SpreadsheetApp.getUi().alert('Future Date Error');
break;
}
}
}
The problem i have is, it throws alert Future Date Error irrespective of date in column (Referral Date). Let me know if additional information is required.
My goal:
1)if date column (Referral Date) is greater than present date : Throw alert error & should not run updateFilter
2)if (Referral Date) is lesser than present date: Run updateFilter function
Issues
searchRange.getValues() yields a two dimensional array. So dates[0][0] points to a date, while dates[0] points to an array.
var dates = searchRange.getValues(); is being called inside the loop repeatedly, when it should ideally be called outside once since the value will not change; calling it inside the loop is costly and redundant
for (i=0;i<range.getLastRow();i++){ the condition can be replaced with i<dates.length if point 2 is followed
if (today.valueOf()>dates.valueOf()){ I believe is supposed to have dates[0] instead
Modified Code
function newF(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Worksheet');
var range = ss.getDataRange();
var headers = range.getValues()[0];
var colIndex = headers.indexOf("Referral Date");
var today = new Date();
var searchRange = ss.getRange(2,colIndex+1,ss.getLastRow()-1);
var dates = searchRange.getValues().map(d=>d[0]);
for (i=0;i<dates.length;i++) {
if (today.valueOf()>dates[i].valueOf()){
updateFilter()
} else {
SpreadsheetApp.getUi().alert('Future Date Error');
break;
}
}
}
To run updateFilter only if no future dates
Replace the loop with the following -
if(dates.some(d => today.valueOf() < d.valueOf())) {
SpreadsheetApp.getUi().alert('Future Date Error');
} else {
for (let i=0; i<dates.length; i++) {
updateFilter();
}
}
So I want to create a task/todo model for my app and for every task I want to have a nice looking date and time of creation in the footer. I have already achieved this successfuly on a similar client side only app,:
function getCurrentDateTime () {
const date = new Date();
let day = date.getDate().toString().length <= 1 ? '0' + date.getDate() : date.getDate();
let month = date.getMonth().toString().length <= 1 ? `0${parseInt(date.getMonth() + 1)}` : date.getMonth();
let year = date.getFullYear().toString().length <= 1 ? '0' + date.getFullYear() : date.getFullYear();
let hours = date.getHours().toString().length <= 1 ? '0' + date.getHours() : date.getHours();
let minutes = date.getMinutes().toString().length <= 1 ? '0' + date.getMinutes() : date.getMinutes();
let seconds = date.getSeconds().toString().length <= 1 ? '0' + date.getSeconds() : date.getSeconds();
return { day, month, year, hours, minutes, seconds };
}
function createTask (statePlaceholder, currentTaskText) {
let newTask = {
id: uuid(),
text: currentTaskText,
completed: false,
creationDateTime: {
date: `${getCurrentDateTime().day}/${getCurrentDateTime().month}/${getCurrentDateTime().year}`,
time: `${getCurrentDateTime().hours}:${getCurrentDateTime().minutes}:${getCurrentDateTime().seconds}`
}
};
...
}
and it looks like this:
I want to save all the tasks elements(text, completed or not and date/time of creation) on MongoDB, and I don't know how to define the date and time so that I get what you see in the image, but comming from MongoDB.
const TaskSchema = new mongoose.Schema({
text: { type: String, required: true },
completed: Boolean,
creationDateTime: {
date: // day/month/year,
time: // timestamp
}
});
How can I properly define the date and time on the mongoose schema defined by me?
What you're trying to store as creationDateTime should definitely be of type Date and you should not store it as string or object. It will make any future querying easier and will let you avoid some unexpected issues which may happen if you stored this value as string. You can take advantage of mongoose's default feature which will run Date.now any time you store a new document so your schema can look like this:
const TaskSchema = new mongoose.Schema({
text: { type: String, required: true },
completed: Boolean,
creationDateTime: {
type: Date,
default: Date.now
}
});
When it comes to formatting, mongoose offers a nice capability of defining virtual properties. Such field will not be stored in a database but will by dynamically evaluated and this is where you can reuse your formatting logic:
function dateTimeToParts(date) {
let day = date.getDate().toString().length <= 1 ? '0' + date.getDate() : date.getDate();
let month = date.getMonth().toString().length <= 1 ? `0${parseInt(date.getMonth() + 1)}`: date.getMonth();
let year = date.getFullYear().toString().length <= 1 ? '0' + date.getFullYear() : date.getFullYear();
let hours = date.getHours().toString().length <= 1 ? '0' + date.getHours() : date.getHours();
let minutes = date.getMinutes().toString().length <= 1 ? '0' + date.getMinutes() : date.getMinutes();
let seconds = date.getSeconds().toString().length <= 1 ? '0' + date.getSeconds() : date.getSeconds();
return { day, month, year, hours, minutes, seconds };
}
TaskSchema.virtual('createdOn').get(function() {
let { day, month, year, hours, minutes, seconds } = dateTimeToParts(
this.creationDateTime
);
return {
date: `${day}/${month}/${year}`,
time: `${hours}:${minutes}:${seconds}`
};
});
So having below document in your MongoDB database:
{
"_id" : ObjectId("5e2e7c93397e8124b81dfcaa"),
"creationDateTime" : ISODate("2020-01-27T06:00:51.409Z"),
"text" : "abc",
"__v" : 0
}
You can run following code:
let task = await Task.findOne({ _id: ObjectId("5e2e7c93397e8124b81dfcaa") });
console.log(task.createdOn);
To get following output:
{ date: '26/01/2020', time: '22:00:51' }
I'm new to protractor and I'm verifying that the default values in some drop downs are the current date: month, day and year
This is my code which I wrote:
this.startDateMonthDropdown = element(by.xpath("//op-dropdown[#change.bind='changeStartMonth']"));
this.startDayInput = element(by.xpath("//input[#value.two-way='startDay']"));
this.startYearDropdown = element(by.xpath("//op-dropdown[#change.bind='changeStartYear']"));
function checkStartDateIsCurrentDate() {
let date = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
let currentMonth = date.getMonth() + 1;
let currentDay = date.getDate() - 1;
let currentYear = date.getFullYear();
this.startDateMonthDropdown.getText().then(function (month) {
expect(month).toEqual(currentMonth)
});
this.startDayInput.getAttribute('value').then(function (day) {
expect(day).toEqual(currentDay)
});
this.startYearDropdown.getText().then(function (year) {
expect(year).toEqual(currentYear)
});
}
When I run the test, it fails:
Expected 'July' to equal 7.
Expected '4' to equal 4.
Expected '2019' to equal 2019.
The getText() method returns a promise that will be resolved with the element's visible text (string). So you have to convert currentDay and currentYear to the string.
function checkStartDateIsCurrentDate() {
const date = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
const currentMonth = date.toLocaleString('en-us', { month: 'long' });
const currentDay = date.getDate() - 1;
const currentYear = date.getFullYear();
this.startDateMonthDropdown.getText().then(function (month) {
expect(month).toBe(currentMonth)
});
this.startDayInput.getAttribute('value').then(function (day) {
expect(day).toBe(`${currentDay}`)
});
this.startYearDropdown.getText().then(function (year) {
expect(year).toBe(`${currentYear}`)
});
}
Expected '4' to equal 4.
Expected '2019' to equal 2019.
When you interact with an element and write getText(). It takes values as text but if you want to compare with number then you must convert text to number and then verify that.
thank you for the answers. I managed to fix it and also solved the issue with the month.
This is my final code
function checkStartDateIsCurrentDate() {
let date = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
let currentMonth = date.getMonth();
let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
let currentDay = date.getDate() - 1;
let currentYear = date.getFullYear();
this.startDateMonthDropdown.getText().then(function (month) {
expect(month).toEqual(months[currentMonth])
});
this.startDayInput.getAttribute('value').then(function (day) {
day = parseInt(day);
expect(day).toEqual(currentDay)
});
this.startYearDropdown.getText().then(function (year) {
year = parseInt(year);
expect(year).toEqual(currentYear)
});
}
Here is what I want to do:
I got a date range from e.g. 03.04.2013 to 23.04.2013 - that's my main range.
Now I have the possibility to create some own time ranges (e.g. 04.04.2013 to 09.04.2013 and 11.04.2013 to 23.04.2013). Those have to cover the whole main range, so every day of the main range (excluding weekens) needs an corresponding day in my own time ranges.
My plan would be to create an Array for the main range. Then I check each day of my own time ranges against the main range. If there is an accordance, I would remove the day from the main range.
So in the end, if everything is ok, there would be an emtpy array, because all days are covered by my own time ranges. If not, then the days not covered would still be in the main range and I could work with them (in this example: 03.04.2013, 10.04.2013)
Does anybody have an better idea to solve this problem? NotesDateTimeRanges?
I would add the dates into a sorted collection and then a "pirate algorithm". Look left, look right and if any of the looks fails you can stop (unless you want to find all missing dates).
Off my head (you might need to massage the final list to store the value back):
var AbsenctSince:NotesDateTime; //Start Date - stored in the NotesItem
var endDate:NotesDateTime; // Return, could be in Notes or Today
var wfDoc:NotesDocument = docApplication.getDocument();
var responseCDs:NotesDocumentCollection = wfDoc.getResponses();
var docResponse:NotesDocument;
var nextResponse:NotesDocument;
//Get the date, which limits the function - if there is a return information, then this is the limit, else today
AbsenctSince = wfDoc.getDateTimeValue("AbsentSince") ;
if (wfDoc.hasItem("ReturnInformationDat")) {
endDate = wfDoc.getDateTimeValue("ReturnInformationDat");
} else {
endDate = session.createDateTime("Today");
}
//Get all days between two dates - as pure Java!
var dateList:java.util.List = getWorkDayList(AbsenctSince.toJavaDate(), endDate.toJavaDate());
// Looping once through the reponse documents
var docResponse = responseCDs.getFirstDocument();
while (docResponse != null) {
nextResponse = responseCDs.getNextDocument(docResponse);
var CDValidSince:NotesDateTime = docResponse.getDateTimeValue("CDValidSince");
var CDValidTill:NotesDateTime = docResponse.getDateTimeValue("CDValidTill");
// Now we need get all days in this range
var removeDates:java.util.List = getWorkDayList(CDValidSince.toJavaDate(),CDValidTill.toJavaDate());
dateList.removeAll(removeDates);
docResponse.recycle();
docResponse = nextResponse;
}
// Both docs are null - nothing to recycle left
// Now we only have uncovered dates left in dateList
docApplication.replaceItemValue("openDates", dateList);
// Cleanup
try {
AbsenctSince.recycle();
endDate.recyle();
wfDoc.recycle();
responseCDs.recycle();
} catch (e) {
dBar.error(e);
}
function getWorkDayList(startDate, endDate) {
var dates:java.util.List = new java.util.ArrayList();
var calendar:java.util.Calendar = new java.util.GregorianCalendar();
calendar.setTime(startDate);
while (calendar.getTime().before(endDate)) {
var workDay = calendar.get(calendar.DAY_OF_WEEK);
if (workDay != calendar.SATURDAY && workDay != calendar.SUNDAY) {
var result = calendar.getTime();
dates.add(result);
}
calendar.add(java.util.Calendar.DATE, 1);
}
return dates;
}
I've done it this way now (seems to work so far):
var dateArray = new Array();
var responseCDs:NotesDocumentCollection = docApplication.getDocument().getResponses();
var dt:NotesDateTime = session.createDateTime("Today");
var wfDoc = docApplication.getDocument();
dt.setNow();
//Get the date, which limits the function - if there is a return information, then this is the limit, else today
var AbsenctSince:NotesDateTime = session.createDateTime(wfDoc.getItemValue("AbsentSince").toString().substr(0,19));
if (wfDoc.hasItem("ReturnInformationDat")) {
var endDate:NotesDateTime = session.createDateTime(wfDoc.getItemValue("ReturnInformationDat").toString().substr(0,19));
} else {
var endDate:NotesDateTime = session.createDateTime("Today");
}
//Get all days between two dates
dateArray = getDates(AbsenctSince, endDate);
for (var i=dateArray.length-1; i >= 0 ; i--) {
var checkDate:NotesDateTime = session.createDateTime(dateArray[i].toString().substr(0,19));
var day = checkDate.toJavaDate().getDay();
//Remove weekends first
if ((day == 6) || (day == 0)) { //6 = Saturday, 0 = Sunday
dBar.info("splice: " + dateArray[i]);
dateArray = dateArray.splice(i,1);
} else {
var docResponse = responseCDs.getFirstDocument();
//Work through all response docs to check if any date is covered
while (docResponse != null) {
var CDValidSince:NotesDateTime = session.createDateTime(docResponse.getItemValue("CDValidSince").toString().substr(0,19));
var CDValidTill:NotesDateTime = session.createDateTime(docResponse.getItemValue("CDValidTill").toString().substr(0,19));
//checkDate covered? If yes, it will be removed
if (checkDate.timeDifference(CDValidSince)/86400 >= 0 && checkDate.timeDifference(CDValidTill)/86400 <= 0 ) {
dBar.info("splice: " + dateArray[i]);
dateArray = dateArray.splice(i,1);
}
docResponse = responseCDs.getNextDocument();
}
}
}
docApplication.replaceItemValue("openDates", dateArray);
And I'm using this function (adopted from this question here):
function getDates(startDate:NotesDateTime, endDate:NotesDateTime) {
var dateArray = new Array();
var currentDate:NotesDateTime = startDate;
while (endDate.timeDifference(currentDate) > 0) {
dateArray.push( currentDate.getDateOnly() );
currentDate.adjustDay(1);
}
return dateArray;
}