Switch row background based on date on Google spreadsheet - google-sheets

I have a column that store the date and I try to implement a conditional formatting custom formula that switch background color of an entire row (or multiple cells of a row) if the day is odd or even.
Here is a coma separated value version of my sheet and what I try to achieve. Date and time are in separate columns. I can have multiple rows with the same date (different times). Rows with the same date must have the same color.
Date, Time, Data
01/12/2014, 01:00, "xxxx" -> BG = X
01/12/2014, 03:00, "xxxx" -> BG = X
02/12/2014, 01:00, "xxxx" -> BG = Y
03/12/2014, 01:00, "xxxx" -> BG = X
03/12/2014, 02:00, "xxxx" -> BG = X
04/12/2014, 03:00, "xxxx" -> BG = Y
To compute if the day is even or odd, I wrote a simple function that return the number of days since 01/01/1970:
/**
* Return the day of the year of a date or a range
*
* #param {date}|{Array.Array} Date or range.
* #return The day of year.
* #customfunction
*/
function DAYSFROM70(date)
{
if (date.map) {
return date.map(DAYSFROM70);
} else {
if (!date instanceof Date || !date.getTime) {
return "";
} else {
return Math.ceil(date.getTime() / 86400000);
}
}
}
And this is the custom formula I tried to apply (note that DAYSFROm70 function is using a range as parameter), without success:
=ISODD(DAYSFROM70($B$2:$B$101))
The following formula does color cells backgrounds (but I obviously can't use that, sunday and monday are both odd):
=ISODD(WEEKDAY($B$2:$B$101))
Something is wrong with my script but I can't figure out what...
Check out this spreadsheet for testing:
https://docs.google.com/spreadsheets/d/1U49FoeMPKlvjCURsqS7GxTH62u_fTJNCcH12XFQtWVQ
Thanks for your help.

why cant you just do: =isodd(day(A1)) ??
select whole sheet
click format -> conditional formatting
from the dropdown choose "custom formula"
in the formula box put: =isodd(day($A1))
select your format (background color)
click ok.
edit
in your question you did not speciffy what you meant by "day is odd".
since you want to colour rows for "every other day" irrespective of day of year, month, or year you can just do (using build in functions):
=isodd(DATEVALUE($A1))
[please read instructions above on applying the conditional formula. You DO NOT need to use a range or array]
DO NOT REFER TO A RANGE IN THE CONDITIONAL FORMATTING FORMULA!! "=ISEVEN(WEEKDAY($B$2:$B$23))" <- NO!!
"=isodd(DATEVALUE($A2))" <- YES!! (where A2 is the topmost row of the range you are formatting - as written in the "range" box in the conditional formatting popup dialog)

It seems Google Spreadsheet doesn't support dates in that format. Using your function, I get an error when trying that format, but if I remove the times from the end, it works fine.
Work around: Add the date as a custom format: https://support.google.com/docs/answer/56470?hl=en
I got it work with: "12/1/2014 1:00:00" by setting the format:
Year(1930)-Month(08)-Day(05),Hour(1):Minute(1)
----EDIT-----
I set the conditional formatting to:
=ISODD(DAYSFROM70($A1))
I had the dates in column A, so this will change the entire row is the date is odd.
Hope this helps

If your dates are in ColumnA please try Format, Conditional formatting..., Custom formula is :
=isodd(text($A1,"#"))
with formatting of choice applied to Range: A:Z (or extended as required).

Related

Default value in data validation dropdown

I have a table that changes dynamically based on the week we're on by using
=WEEKNUM(TODAY())
but I want to create a dropdown menu with all the week numbers, so a user can select any week and check the data related to that weeknum. However, I'd like that everytime the sheet opens, it shows as a default, the current weeknum.
You might be able to use a non-script approach if you can adapt the technique outlined in detail at https://www.benlcollins.com/spreadsheets/default-values/. You will need to be able to add a column to the immediate left of the 'Week' column, and probably also to hide the column afterwards for neatness.
For instance, if the example table above was in columns B&C, add the following formula to A2, copy down the column as far as needed then hide column A:
={"",weeknum(today())}
You can then set up the data validation dropdown in the week column, and anything you select in those cells will overwrite the default value. This generates #REF! errors in column A because you are preventing a literal array expanding, but you can't see the error because it's hidden, and you don't care about it anyway. If you delete the value in any cell in the Week column, the array in the corresponding cell in column A will be able to expand again and show the default value once more.
Suggestion
As what #player0 have mentioned, this is possible using a script. You may use this quick sample script below as reference on how to create a drop-down, set it with week numbers from the current week down to the first week of year, and set it up to show the default current week number.
Sample Script:
function test() {
var currentDate = new Date();
var startDate = new Date(currentDate.getFullYear(), 0, 1);
var days = Math.floor((currentDate - startDate) / (24 * 60 * 60 * 1000));
var weekNumber = Math.ceil((currentDate.getDay() + 1 + days) / 7);
var weeks = [];
while (weekNumber != 0) { //Get the week numbers from today to the first week of the year
weeks.push(weekNumber)
weekNumber--;
}
var cell = SpreadsheetApp.getActive().getRange('A1');
var rule = SpreadsheetApp.newDataValidation().requireValueInList(weeks, true).build();
cell.setDataValidation(rule).setValue(weeks[0]); //Sets the default value to the current week number
}
Test
Reference
https://developers.google.com/apps-script/reference/spreadsheet/range#setvaluevalue
https://developers.google.com/apps-script/reference/spreadsheet/data-validation-builder#requirevalueinlistvalues

G Sheets cond column-wide formatting IF the date is in next 3 days AND it is Monday

A header
B header
C header
First
01.01.2000
something
Second
02.01.2000
something
I have a sheet with B column filled with dates.
I have 4 conditional formattings: today, tomorrow and "overmorrow" dates.
The fourth condition is the following:
Mark the cell IF its date is today()+3 AND its weekday is Monday.
The simple options "date is exactly" works for "today()+2". But it declines to works with =and() formula. It should get the date type, not a boolean.
As for the formula option, I cannot invent the right formula. This doesn't work:
=and(today()+2,weekday()=2) - I believe that, when you select a non-simple option (not like date -> is exactly) it should take the real arguments, and should not contain empty function calls like weekday().
enter image description here
You should use this custom formula: =AND(B1=today()+2,weekday(B1)=2)
Sample:
Custom formula: =AND(B1=today()+3,weekday(B1)=2)
Note: I used today()+3 temporarily just to show that the conditional formatting is working since my current day is friday.

How to generate random data of birth dates using google spreadsheets for a specific years?

I want a formula to generate random data of birth dates for a specific years (Example: 1995 to 2002) and make it Array like this:
Sheet URL: https://docs.google.com/spreadsheets/d/1XHoxD-hNmpUOMVm_u-cz-4ESrabodsrS0fIfaN-n4js/edit
That might not be the best approach but it will get you closer to what you want:
=DATE(RANDBETWEEN(1995,2002),RANDBETWEEN(1,12),RANDBETWEEN(1,31))
There are two issues with this approach:
you might get a day that does not exist for the particular month. For example, 2/28/2021 exists, but 2/29/2021 does not exist.
I wasn't able to generate an array but only drag down formulas. When I generate an array, the same random numbers are used and as a result the dates are the same.
For the first issue, you can use isdate to check if the random date returned is correct. For example, 2/29/2021 is a wrong date (I hardcopied that date).
but I guess you can filter out the FALSE cases.
I really hope other people can come up with a better approach.
You could try (as I demonstrated in your sheet):
=ARRAY_CONSTRAIN(SORT(SEQUENCE(DATE(1992,12,31)-DATE(1900,1,1),1,DATE(1900,1,1)),RANDARRAY(DATE(1992,12,31)-DATE(1900,1,1)),1),COUNTA(A2:A),1)
SEQUENCE(DATE(1992,12,31)-DATE(1900,1,1),1,DATE(1900,1,1)) - Is used to create an array of valid numeric representations of true dates between 1-1-1900 and 31-12-1992.
SORT(<TheAbove>,RANDARRAY(DATE(1992,12,31)-DATE(1900,1,1)),1) - Is used to sort the array we just created randomly.
ARRAY_CONSTRAIN(<TheAbove>, COUNTA(A2:A),1) - Is used to only return as many random birth-dates we need according to other data.
Note that this is volatile and will recalculate upon sheet-changes and such. Also note that this is just "slicing" a given array and may fall short when you try to use it on a dataset larger than the given array.
As Google Sheets can deal with dates as integers (~ number of days since 1900), choosing a random date between two dates can be a single call to RANDBETWEEN (with the output formatted as Date).
With your initial date written in B1 and your end date in B2, the formula is simply:
=RANDBETWEEN($B$1,$B$2)
You can paste this formula in as many cells as you want, to generate N different random dates.
Of course, as other answers involving random generators in your sheet, the formula will be recomputed at each change. My suggestion to overcome this would simply be to copy/paste the output, using the "Paste special > Values only" option (right click or "Edit" menu).
Script Solution
Just for sake of completeness, here is a solution using a script
Initial Considerations
This cannot function like a in sheet function/formula.
https://developers.google.com/apps-script/guides/sheets/functions
Custom function arguments must be deterministic. That is, built-in spreadsheet functions that return a different result each time they calculate — such as NOW() or RAND() — are not allowed as arguments to a custom function. If a custom function tries to return a value based on one of these volatile built-in functions, it will display Loading... indefinitely.
A custom function cannot affect cells other than those it returns a value to. In other words, a custom function cannot edit arbitrary cells, only the cells it is called from and their adjacent cells. To edit arbitrary cells, use a custom menu to run a function instead.
So a normal script is needed.
The Script
/**
* Sets the values of a range to random dates.
*/
function generateRandomBdays(range, start, end) {
let height = range.getHeight();
let width = range.getWidth();
let output = [];
for (let i = 0; i != height; i++) {
let row = [];
for (let j = 0; j != width; j++) {
row.push(randomBday(start, end));
}
output.push(row)
}
range.setValues(output);
}
/**
* Generates a random date beween start and end
*/
function randomBday(start, end) {
if (start < 2000) start = start - 1900
start = new Date(`${start}`);
if (end < 2000) end = end - 1900
end = new Date(`${end}`);
let bday = new Date(
start.getTime() + (Math.random() * (end.getTime() - start.getTime()))
);
return bday;
}
/**
* Gets active selection and fills with random dates
*/
function main(){
let file = SpreadsheetApp.getActive();
let sheet = file.getActiveSheet()
let range = sheet.getActiveRange();
// ============
generateRandomBdays(range, 1995, 2002); // Change these years to your liking
// ============
}
/**
* Creates menu when sheet is opened.
*/
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Generate Birthdays')
.addItem('Generate!', 'main')
.addToUi();
}
Which works like this:
Installation
You will have to copy it into your script editor and then run one of the functions to authorize the script with the permissions it needs. Then next time you open the sheet you should have the menu available.
Alternatively you can delete the onOpen function and just use it from the script editor.
Within the main function, customize the range of years you need.
References
Apps Script
Overview of Spreadsheet Service in Apps Script

Display text representation of a date as a formula result

I get this date format from Zapier
2018-08-16T01:13:58
I use this formula to split and extract the first half of the split (the date).
=index(SPLIT("2018-08-16T01:13:58","T"),0,1)
Google Sheets displays the formula output as a number, e.g. 43328
If I format this cell manually, using the menu Format >> Number >> Date, Google Sheets will display it as the formatted date, e.g. 16/08/2018
If I use DATEVALUE() as such:
=datevalue(index(SPLIT("2018-08-16T01:13:58","T"),0,1))
then the cell displays #VALUE!
Error DATEVALUE parameter '43328' cannot be parsed to date/time.
How can I write my formula such that it is displayed as formatted date, without having to format the formula's cell through the menu?
You can use the TEXT function:
=TEXT(43328,"dd-mm-yyyy")
Date shows in google spreadsheet are formatted by google spreadsheet settings. If you want to change the datetime format of your sheet, you will have to change Locale setting to that of your need.
If you don't want to go over settings, you can set it manually by code.
First, you will need to put this formula =SPLIT("2018-08-16T01:13:58","T") + "" somewhere to get the date value. Here I assume you use cell "Z1"
Now, you will have to change the date format each time "Z1" changes it value. I use onEdit(e)
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSheet()
if (range.getColumn() == 26 && range.getRow() == 1) { // if Z1 is modified
var d = ss.getRange("Z1").getValue()
var inputDate = Utilities.formatDate(d, "GMT+7", "dd/MM/yyyy")
ss.getRange("B5").setValue(inputDate)
}
}
There you go. Each time Z1 change, which means the date value is inputted, the correct date + format will be reflected in B5.
After much searching this seems to work for me.
=regexreplace(SUBSTITUTE(SPLIT("2018-08-16T10:02:29","T") + "","-","/"), "^(\d+).(\d+).(\d+)$", "$3/$2/$1") & " " & regexreplace(RIGHT("2018-08-16T10:02:29", find("T","2018-08-16T10:02:29") -3), "^(?:(?:([01]?\d|2[0-3]):)?([0-5]?\d):)?([0-5]?\d)$", "$1:$2:$3")
Outputs 16/08/2018 10:02:29

Cleaner formula for subtracting a set amount from a column of values each calendar day in google sheets?

Formula: In cell A1 I manually type the date that I'm adding a new value, in cell B1 I have the Today() formula, and finally in cell C1 I have the formula =YourStartingValue - (5*(B1-A1)).
Result: The end result is that the value I input into cell C1 gets 5 subtracted from it each new calendar day. I then repeat this step in a new row for each new value that I add.
My question: is there a formula I can use so that I don't have to add the stuff in A1 and B1 each time? It'd save time and make things cleaner. Thanks!
In order to have 5 subtracted from every value in some column every day, I would use a script such as this one:
function subtractDaily() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var range = sheet.getRange('C:C');
var values = range.getValues();
range.setValues(values.map(function(row) {
return [row[0] == parseFloat(row[0]) ? row[0] - 5 : row[0]];
}));
}
Change the sheet name and column as needed, and set it to run daily using "Resources > Current project's triggers" dialog of the script editor.
The script checks that the cells contain numbers and does not attempt to subtract 5 from text or blank cells.

Resources