I'm using Google sheets for data entry that auto-populates data from my website whenever someone submits to a form. The user's data imports into my sheet with a timestamp (column A).
Using the Arrayformula function, I'd like a column to autofill all the dates of a timestamp within that month. For example, if 1/5/2016 is entered as a timestamp, I'd like the formula to autofill in the dates 1/1/2016 - 1/31/2016.
Additionally, I'd like other months added in the Arrayformula column. For example, if both 1/5/2016 and 2/3/2016 are entered in column A, I'd like the formula to fill in the dates from 1/1/2016 - 2/29/2016.
I know I can manually write in the dates and drag them down the column, but I have a lot of sheets, and using an Arrayformula will save me a lot of time. I've tried a similar formula in column B, but it doesn't autofill in the date gaps. Is what I'm looking for possible?
Here's a copy of the editable spreadsheet I'm referring to: https://docs.google.com/a/flyingfx.com/spreadsheets/d/1Ka3cZfeXlIKfNzXwNCOWV15o74Bqp-4zaj_twC3v1KA/edit?usp=sharing
Short answer
Cell A1
1/1/2016
Cell A2
=ArrayFormula(ADD(A1,row(INDIRECT("A1:A"&30))))
Explanation
In Google Sheets dates are serialized numbers where integers are days and fractions are hours, minutes and so on. Once to have this in mind, the next is to find a useful construct.
INDIRECT(reference_string,use_A1_notation) is used to calculate a range of the desired size by given the height as a hardcoded constant, in this case 30. You should not worry about circular references in this construct.
ROW(reference) returns an array of consecutive numbers.
A1 is the starting date.
ADD(value1,value2). It's the same as using +. As the first argument is a scalar value and second argument is an array of values, it returns an array of the same size of the second argument.
ArrayFormula(array_formula) displays the values returned by array_formula
As A1 is a date, by default the returned values will be formatted as date too.
Increment by Month
If anyone wants to be able to increment by month, here's a way I've been able to accomplish that. Your solution #ptim got me on the right track, thanks.
Formula
Placed in B1
First_Month = 2020-11-01 [named range]
=ARRAYFORMULA(
IF(
ROW(A:A) = 1,
"Date",
IF(
LEN(A:A),
EDATE( First_Month, ROW( A:A ) -2 ),
""
)
)
)
Result
ID Month
1 2020-11-01
2 2020-12-01
3 2021-01-01
4 2021-02-01
5 2021-03-01
I have an alternative to the above, which allows you to edit only the first row, then add protection (as I like to do with the entire first row where I use this approach for other formulas):
=ARRAYFORMULA(
IF(
ROW(A1:A) = 1,
"Date",
IF(
ROW(A1:A) = 2,
DATE(2020, 1, 1),
DATE(2020, 1, 1) + (ROW(A1:A) - 2)
)
)
)
// pseudo code!
const START_DATE = 2020-01-01
if (currentRow == 1)
print "Date"
else if (currentRow == 2)
print START_DATE
else
print START_DATE + (currentRow - 2)
Notes:
the initial date is hard-coded (ensure that the two instances match!)
ROW(A1:1) returns the current row number, so the first if statement evaluates as "if this is Row 1, then render Date"
"if this is row 2, render the hard-coded date"
(nB: adding an integer to a date adds a day)
"else increment the date in A2 by the (adjusted) number of rows" (the minus two accounts for the two rows handled by the first two ifs (A1 and A2). Eg: in row 3, we want to add 1 to the date in row 2, so current:3 - 2 = 1.
Here's a live example (I added conditional formatting to even months to assist sanity checking that the last day of month is correct):
https://docs.google.com/spreadsheets/d/1seS00_w6kTazSNtrxTrGzuqzDpeG1VtFCKpiT_5C8QI/view#gid=0
Also - I find the following VScode extension handy for syntax highlighting Google Sheets formulas: https://github.com/leonidasIIV/vsc_sheets_formula_extension
The Row1 header trick is courtesy of Randy via https://www.tillerhq.com/what-are-your-favorite-google-spreadsheet-party-tricks/
nice. thanks.
To get the list length to adapt to the number of days in the selected month simply replace the static 30 by eomonth(A1;0)-A1. This accommodates for months with 31 days, and for February which can have either 28 or 29 days.
=ArrayFormula(ADD(A1,row(INDIRECT("A1:A"&eomonth(A1;0)-A1))))
Updated for 2022:
This can now be done pretty easily with the SEQUENCE function, it's also a bit more adaptable.
Below will list all of the days in columns but you can swap the first 2 values to place in rows instead:
=SEQUENCE(1,7,today()-7,1)
More specific to your example, below will take the date entered (via cell, formula, or named cell) and give you the full month in columns:
=SEQUENCE(1,day(EOMONTH("2016-1-5",0)),EOMONTH("2016-1-5",-1)+1,1)
Related
I am trying to build a sleep tracker in Google Sheets (link). The idea is to select a year and a month from a drop-down list in cells A1 and A2, which would then populate columns based on the number of days in that month. I have tried different formulas that I found on stack overflow and elsewhere, but could not get them to work.
In short:
I am looking for a formula that will populate the columns with days of that month and a name of the day in a row bellow.
Looking for a way to summarize the time of sleep at the end of the each day, based on a ticked checkbox.
I am not sure how the year and month selectors should be formatted (as plain number or a date).
Is there a way to automatically insert check-boxes to the days of the month?
This is the formula that I have tried to adjust:
=INDEX({TEXT(SEQUENCE(1; DAY(EOMONTH(A2&"/"&A1;0)); A2&"/"&A1; 1); {"d"; "ddd"}); {"Total"; ""}})
But it returns with "Error In ARRAY_LITERAL, an Array Literal was missing values for one or more rows."
Please note that ";" is used as an argument separator instead of "," (regional settings).
Thank you in advance!
I think that with a very small adaptation and date formatting you'll be able to easily do it. First with your selector in A2, you could set it as actual dates, but format them as mmmm:
Then, repeat the sequence in both rows starting in C2 and C3:
=SEQUENCE(1,DAY(EOMONTH(A2,0)),A2)
But formatting row 3 as ddd:
PS: yes, you can do row 3 with TEXT and INDEX. Choose your preferred one:
=INDEX(TEXT(SEQUENCE(1,DAY(EOMONTH(A2,0)),A2),"dddd"))
UPDATE with TEXT VALUES
Return to your previous A2 dropdown and try this, using MATCH to find the number of the month, and DATE to locate the correct beginning of the month in that year:
For row 2:
=SEQUENCE(1,DAY(EOMONTH(DATE(A1,MATCH(A2,{"January","February","March","April","May","June","July","September","October","November","December"},0),1),0)),
DATE(A1,MATCH(A2,{"January","February","March","April","May","June","July","September","October","November","December"},0),1))
For row 3:
=INDEX(TEXT(SEQUENCE(1,DAY(EOMONTH(DATE(A1,MATCH(A2,{"January","February","March","April","May","June","July","September","October","November","December"},0),1),0)),
DATE(A1,MATCH(A2,{"January","February","March","April","May","June","July","September","October","November","December"},0),1)),"dddd")
)
I have sales data that gives me dates in a bad format. Every new sale gets automatically added to the sheet. Looks like this:
Column A
Column B
Column C
Order 1
2022-12-02T02:09:37Z
$1025.19
Order 2
2022-12-02T01:25:15Z
$873.65
This will continue on for all sales. Now the date format is UTC for whatever reason and I can't adjust that, so within this formula I have to subtract 6 hours to get it to central time. I'm trying to create an auto-updating chart that shows an average day for 7 days, so I'm trying to do a sumif formula.
Here's what I have on Sheet2:
=sumif(Sheet1!C:C,index(split((index(split(Sheet1!B:B,"T"),1)+index(split(left(Sheet1!B:B,19),"T"),2))-0.25,"."),1),A1)
Where A1 is a single date. Testing this with one date and not the range shows that it does match. When I do the range, the total comes to 0, even though multiple different dates should match. What am I doing wrong?
Assume A1 has the value: 2022-12-02T02:09:37Z
Apply this formula:
=LAMBDA(RAW,TUNEHOUR,
LAMBDA(DATE,TIME,
TEXT((DATE&" "&TIME)+TUNEHOUR/24,"yyyy-mm-dd hh:mm:ss")
)(TEXT(INDEX(RAW,,1),"yyyy-mm-dd"),REGEXREPLACE(INDEX(RAW,,2),"Z",""))
)(SPLIT(A1,"T"),-6)
returns:
2022-12-01 20:09:37
And assume you have a set of data like this:
you can apply this formula:
=ArrayFormula(
LAMBDA(DATES,AMOUNTS,START,END,DFORMAT,TFORMAT,SKIPBLANK,TUNEHOUR,
LAMBDA(DATES,AMOUNTS,DTFORMAT,START,END,
LAMBDA(DATES,TIMES,
LAMBDA(VALIDDATES,AMOUNTS,
TEXT(SUM(FILTER(AMOUNTS,VALIDDATES>=START,VALIDDATES<=END)),"$#,##0.00")
)(TEXT((DATES&" "&TIMES)+TUNEHOUR/24,DTFORMAT),IF(ISNUMBER(AMOUNTS),AMOUNTS,VALUE(REGEXEXTRACT(AMOUNTS,"^\$(.+)"))))
)(TEXT(INDEX(DATES,,1),DFORMAT),REGEXREPLACE(INDEX(DATES,,2),"Z",""))
)(SPLIT(QUERY({DATES},SKIPBLANK),"T"),QUERY({AMOUNTS},SKIPBLANK),DFORMAT&" "&TFORMAT,TEXT(START,DFORMAT)&" 00:00:00",TEXT(END,DFORMAT)&" 23:59:59")
)($B$5:$B,$C$5:$C,$B$1,$B$2,"yyyy-mm-dd","hh:mm:ss","WHERE Col1 IS NOT NULL",-6)
)
Where you enter a start date and an end date at B1 & B2 to sum up the amount with.
The provided date column will be deducted by 6 hours.
What this formula does is...
format the date column into a valid date,
compare dates from step 1 with a given start and end date as filter condition,
filter the given amount column with conditions from step 2,
sum the result of filter from step 3 as an array,
format the output as price.
Use regexreplace() and query(), like this:
=arrayformula(
query(
{
weeknum(
regexreplace(B2:B, "([-\d]+)T(\d\d:\d\d).+", "$1 $2")
-
"6:00"
),
C2:C
},
"select Col1, avg(Col2)
where Col1 is not null
group by Col1
label Col1 'week #' ",
0
)
)
I think you're trying to split the values and sum them. I can't understand fully what's the purpose of 19 in LEFT function, and why are you again splitting it? Maybe some approach similar to yours is use LEFT function with 10 characters for the date, and MID from 12th character to get the time. Then substract .25 for the 6 hours as you did, and ROUNDDOWN with 0 digits to get the only the day
=ARRAYFORMULA(ROUNDDOWN(LEFT('Sheet1'!B:B,10)+MID('Sheet1'!B:B,12,8)-0.25,0))
And then you can insert it in your SUMIF:
=SUMIF(Sheet1!C:C,ARRAYFORMULA(ROUNDDOWN(LEFT(Sheet1!B:B,10)+MID(Sheet1!B:B,12,8)-0.25,0)),A1)
I'm trying to concatenate a column of dates and other of hours.
The fuction:
=CONCATENATE(TEXT(AGENDA!B9 ,"dd-mm-yyyy"), " ", TEXT(AGENDA!C9 ,"hh:mm:ss"))
works, but, some cells are in fuction format, dd-mm-yyyy, and some others are dd/mm/yyyy (the time is correct). I need them all with -
You have a non valid date in AGENDA sheet Fecha column note Luque, Hugo 20/08/2021 with month set to 20 !! and day is 08.
To add date validation, Select B2:B and go to Data data > validation > Criteria: date.
and select On invalid data: Show warning.
Fix the date one by one or take a look at the quick fix.
To check the date format:
Go to Formst > number > Custom date and time.
The Quick fix
To get date fixed with a formula from, mm/dd/yyyy to dd-mm-yyyy you need a helper column lets call it Fixed Date, with the formula.
=IF(ISDATE(B2)=False,CONCATENATE(INDEX(SPLIT(B2,"/-"),1,2),"-",INDEX(SPLIT(B2,"/-"),1,1),"-",INDEX(SPLIT(B2,"/-"),1,3)),B2)
Explanation
1 - IF(ISDATE(B2)=False check the date is valid if true return the original value example B2 if false calculate the formula.
2 - INDEX(SPLIT(B2,"/-"),1,2) to get the month column that resulted from SPLIT function with column set to 2.
3 - INDEX(SPLIT(B2,"/-"),1,1) to get the day column that resulted from SPLIT function with column set to 1.
4 - INDEX(SPLIT(B2,"/-"),1,3)) to get the yaer column that resulted from SPLIT function with column set to 3.
5 - CONCATENATE the columns with "-" in between.
Now you can paste your formula but adjusted in BBDD.AGENDA Sheet B3 cell.
=TEXTJOIN(" ",TRUE,TEXT(AGENDA!C2 ,"dd-mm-yyyy"),TEXT(AGENDA!D2 ,"hh:mm:ss"))
Notice that we changed AGENDA!B2 with AGENDA!C2.
I am wondering if there is a way to use column comparisons in a SUMIF or SUMIFS function or the DSUM function even. Specifically, I want to compare one value in a row with another value in the same row of data.
For example, let's say I have the following table of data:
Date 1 | Date 2 | Money Earned
1/2/22 | 1/5/22 | $23.00
1/5/22 | 1/3/22 | $11.00
I want to write a formula that sums the values in the 3rd column if Date 1 is last week and if Date 2 is later than or equal to Date 1.
I have completed a workaround solution with 2 hidden columns as follows:
Last week --> =IF(EQ(WEEKNUM(TODAY()) - WEEKNUM(A2), 1), "YES", "NO")
Date 2 After Date 1 --> =IF(B2>=A2, "YES", "NO")
Then I use:
=SUMIFS(C2:C3,D2:D3,"YES",E2:E3,"YES")
It all works, but I am trying to learn to do this a cleaner way without hidden columns that someone might move or delete.
All the examples I can find of SUM or SUMIF rely on the criteria being compared to a singular value that is either hardcoded in the formula or the value of a single cell. I want to compare data from column 1 to column 2 directly for each row. Is this possible with these formulas or any formula in Google Sheets?
In order to check if a date was "last week", you need to consider that the current week might be the first one of the year. So, instead of comparing the WEEKNUM of today with the WEEKNUM of the other date, just compare it to the WEEKNUM of 7 days ago.
Secondly, instead of using "YES" or "NO", you could have used TRUE/FALSE values and remove the need to write IF statements, like this:
last week: =(WEEKNUM(TODAY()-7)=WEEKNUM(A2))
date 2 after date 1: B2>=A2
From there, while it is possible to build an arrayformula for SUMIFS or QUERY, it is easier to just filter the table and sum the results from column C:
=SUM(FILTER(C2:C,WEEKNUM(TODAY()-7)=WEEKNUM(A2:A),B2:B>A2:A))
I am trying to make an automated attendance sheet
I have 2 google sheets,
the first one is the responses from a google form that has the name of the students and the date they attended, so it will have duplicated name and duplicated dates.
The second sheet have the names of the students on the left and the dates on the top.
I am trying to automate the second sheet to put "P" under the date that the student was present and "A" when his name is not in the first sheet with that date.
Best i could do was adding an extra column with the letter "p" in the first sheet and using dget to search for the name and date and output the "p" from the extra column, which only worked for one of them for some reason.
=DGET('ATTENDANCE DATE !B:D, "AT", {"NAME", "DATE"; $H$4,12})
I tried to use query also but no luck.
=QUERY('ATTENDANCE DATE'!B7:D,"
SELECT D
WHERE B MATCHES'"&$H9&"' AND C MATCHES '"&I$2&"'
")
Sorry if my question was confusing.
A good solution is to use 4 formulas to do exactly what you like. Each formula has a function:
B1 formula: generates the headers for all the dates with data.
B2 formula: generates the sub-header with the day of the week for each date.
A3 formula: gets all the names.
B3 formula: gets the attendance values for all users. This is the most complexs one.
Here is how it looks:
A
B
1
< fromula 1 >
2
name
< formula 2 >
3
< formula 3 >
< formula 4 >
Before starting there a few things to note
Questions and more information
Please, if at any point you don't understand something, let me know (I'd like this to be a nice resource on how to do formulas).
Also, at the end I left links to all the formulas I use, so you can see what they exactly do.
Locale
I'm using the English locale. this means that I'm using commas , to separate arguments (instead of ;) and array literals (instead of \). if you have function formatting errors, look into it, as this could be the issue.
Sheet names
I've changed the Sheet's names as they are very long and made the formulas harder to follow. Fell free to replace the names on the formulas back to the original name. Here is how I named them:
ATTENDANCE RESPONSES FROM GOOGLE FORM ⟶ Att
LATE/ABSENT RESPONSES FROM GOOGLE FORM ⟶ Late
Formula format
Almost all formulas require "ARRAYFORMULA" to show their full effects. I won't be adding it everywhere as it could get confusing. If you'd like to see what a formula part (doesn't have an equal sign =) does, go to a sheet and do:
=arrayformula(
<paste formula part>
)
Also, parts that are in <some name> are not literal, and represent the code named in between the brackets.
Formula 1
It can be split into 2 formulas:
Get the ordered unique dates
Add a Reason column for each date
Get the dates
The first thing you can use is UNIQUE to get only the unique ones and SORT to sort them. You also need to get them from both sheets as there could be a day that everyone is absent or another where everyone came. SORT(UNIQUE({Att!B2:B; Late!B2:B})) does most of the trick but you also get empty cells. because of that we add a filter. So together:
SORT(UNIQUE(FILTER({Att!B2:B; Late!B2:B}, {Att!B2:B; Late!B2:B}<>"")))
Adding Reason
The problem of it is that the number of column is not fixed (it grows over time). A good workaround is to concatenate the date with a separator and Reason and then split it again. This only works for columns and generates a 2 column, result. Then it can be moved into a single column by using FLATTEN.
FLATTEN(SPLIT(
<previous part>&"␟Reason",
"␟"
))
I'm using ␟ (Symbol For Unit Separator) as the separator as it indicates exactly what it is and is very-very unlikely to be included in the sheet.
If you use that you'll see that the date is shown in numbers. To Change that we'll format the date before concatenating and splitting:
FLATTEN(SPLIT(
TEXT(
<previous part>,
"dd/mmm/yyyy"
)&"␟Reason",
"␟"
))
Now we need to make it a row instead of a column. There is a function that does that: TRANSPOSE.
Complete formula 1
=ARRAYFORMULA(
TRANSPOSE(FLATTEN(SPLIT(
TEXT(
SORT(UNIQUE(FILTER({Att!B2:B; Late!B2:B}, {Att!B2:B; Late!B2:B}<>""))),
"dd/mmm/yyyy"
)&"␟Reason",
"␟"
)))
)
Formula 2
To add the day of the week we need to format the date with TEST and the format ddd, which is the short-version of the name of the day of the week (Mon, Tue, etc).
TEXT(B1:1, "ddd")
Note though that if the value formatted is already text, it will pass it. Because of that, we need to only do this for the columns with dates. One way that I found is to get the even-numbered columns. TO do that, it's a combination of COLUMN (get the number of the column), MOD (get the module), and IF:
IF(MOD(COLUMN(B1:1),2)=0, <formatted text>, "")
This does what we want but we now get "Sun" on columns that there is nothing. The reason is that empty cells are being interpreted as zeros. Because of that we need to add another condition: the cell is not empty.
IF((MOD(COLUMN(B1:1),2)=0)*(B1:1<>""), <formatted text>, "")
To do the logical and I'm using the product because the formula AND would return a single value ("eats" the passed array).
Complete
=ARRAYFORMULA(
IF(
(MOD(COLUMN(B1:1),2)=0)*(B1:1<>""),
TEXT(B1:1, "dddd"),
""
)
)
Formula 3
The third formula is the simplest and should be self-explanatory:
=ARRAYFORMULA(
SORT(UNIQUE(Att!A2:A))
)
Formula 4
This is the final formula. This formula is based on using VLOOKUP to know the value for each person and date.
Making a table to VLOOKUP into
The way of doing that is to generate a key by joining both values into a single text value and set the other values on the other columns. To prevent problems we add a separator to make sure that there are no combination that will be equal. Here is how the table to lookup into looks like:
< name >␟< date >
< status >
< reason >
< name >␟< date >
< status >
< reason >
< name >␟< date >
< status >
< reason >
⋮
⋮
⋮
The key for the first sheet is:
Att!$A$2:$A&"␟"&Att!$B$2:$B
To add the other 2 columns (Present and an empty one) we use a similar trick to Formula 1: we add a separator to split it later on. Because we already are using ␟ for the key, we need another one. In the same block there is another meant for this cases: ␞ (Symbol For Record Separator).
Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞"&"Present"&"␞"&""
or joining the literal text:
Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞Present␞"
This need to be filtered, as there are empty values, which we don't want. We'll use FILTER to do exactly that:
FILTER(Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞Present␞", Att!$A$2:$A<>"", Att!$B$2:$B<>"")
For the second sheet, we do something similar but including the other columns:
FILTER(Late!$A$2:$A&"␟"&Late!$B$2:$B&"␞"&Late!$C$2:$C&"␞"&Late!$D$2:$D, Late!$A$2:$A<>"", Late!$B$2:$B<>"", Late!$C$2:$C<>"")
Note that I've added more conditionals.
This needs to be vertically joined. This can be done with an array literal:
{
<Attr formula>;
<Late formula>
}
Then we need to split the rows to expand into the multiple columns:
SPLIT(
{
FILTER(Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞Present␞", Att!$A$2:$A<>"", Att!$B$2:$B<>"");
FILTER(Late!$A$2:$A&"␟"&Late!$B$2:$B&"␞"&Late!$C$2:$C&"␞"&Late!$D$2:$D, Late!$A$2:$A<>"", Late!$B$2:$B<>"", Late!$C$2:$C<>"")
},
"␞"
)
Using VLOOKUP
Now that we have where to lookup into, we can do it like so:
VLOOKUP(
A3:A&"␟"&C1:1,
<lookup table>,
2,
false
)
Note that the key that we are looking up is the one we generate. Also, this will get the values only below the dates (will fail otherwise).
Adding the reason
Since we know that the cells which are for the reason fail (since <name>␟Reason shouldn't exist), we can use IFERROR to detect it:
IFERROR(
<vlookup status>,
<vlookup reason>
)
The formula for reason is almost identical to the one for status. The only changes are that we lookup into the third column (instead of the second) and we look one to the left:
VLOOKUP(
A3:A&"␟"&OFFSET(C1:1, 0, -1),
<lookup table>,
3,
false
),
Using OFFSET instead of a range ensures that they have the same size.
Final error management
This formula fails when the key doesn't have name or date (which is outside the table or there that entry missing). For that case we add another IFERROR:
IFERROR(
<formula>,
""
)
Complete formula
=ARRAYFORMULA(
IFERROR(
IFERROR(
VLOOKUP(
A3:A&"␟"&C1:1,
SPLIT(
{
FILTER(Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞Present␞", Att!$A$2:$A<>"", Att!$B$2:$B<>"");
FILTER(Late!$A$2:$A&"␟"&Late!$B$2:$B&"␞"&Late!$C$2:$C&"␞"&Late!$D$2:$D, Late!$A$2:$A<>"", Late!$B$2:$B<>"", Late!$C$2:$C<>"")
},
"␞"
),
2,
false
),
VLOOKUP(
A3:A&"␟"&OFFSET(C1:1, 0, -1),
SPLIT(
{
FILTER(Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞Present␞", Att!$A$2:$A<>"", Att!$B$2:$B<>"");
FILTER(Late!$A$2:$A&"␟"&Late!$B$2:$B&"␞"&Late!$C$2:$C&"␞"&Late!$D$2:$D, Late!$A$2:$A<>"", Late!$B$2:$B<>"", Late!$C$2:$C<>"")
},
"␞"
),
3,
false
)
),
""
)
)
Final touches
The final result is something like this.
After that you can simply add formats to your taste. You can also add conditionals ones to more easily see the result.
References
MOD (Google Editors Help)
SPLIT (Google Editors Help)
TEXT (Google Editors Help)
IF (Google Editors Help)
IFERROR (Google Editors Help)
FILTER (Google Editors Help)
UNIQUE (Google Editors Help)
SORT (Google Editors Help)
TRANSPOSE (Google Editors Help)
FLATTEN (Google Editors Help)
ARRAYFORMULA (Google Editors Help)
VLOOKUP (Google Editors Help)
OFFSET (Google Editors Help)
I've completed a not-so-neat solution for you, starting on Row10 in the 'AUTO ATTENDANCE' sheet. It's divided into 4 parts:
The formula in cell D10 auto-populates Row10 with dates and empty cells in between:
=SPLIT(JOIN("|REASON|",SORT(UNIQUE({'ATTENDANCE RESPONSES FROM GOOGLE FORM'!$B$2:$B;'LATE/ABSENT RESPONSES FROM GOOGLE FORM'!$B$2:$B}))),"|")
Row 11 gets the day of the week from row 10 (if the cell above it contains a date:
=IF(ISDATE(D10),TEXT(D10,"dddd"),)
Cell C12 gets all unique names from both response sheets (auto-populates the name column):
=SORT(UNIQUE({'ATTENDANCE RESPONSES FROM GOOGLE FORM'!$A$2:$A;'LATE/ABSENT RESPONSES FROM GOOGLE FORM'!$A$11:$A}))
Cell D12 onwards gets the form responses and does the auto-attendance:
=IF($C12<>"", IF(ISDATE(D$1), IF(IFERROR(QUERY('ATTENDANCE RESPONSES FROM GOOGLE FORM'!$A$2:$B,"select A where A = '"&$C12&"' AND B = datetime '"&TEXT(D$1, "yyyy-mm-dd hh:mm:ss")&"'"), "noresult")=$C12, "PRESENT", IFERROR(QUERY('LATE/ABSENT RESPONSES FROM GOOGLE FORM'!$A$2:$D, "select C where A = '"&$C12&"' and B = datetime '"&TEXT(D$1, "yyyy-mm-d hh:mm:ss")&"'"), "NO RESPONSE")), IFERROR(QUERY('LATE/ABSENT RESPONSES FROM GOOGLE FORM'!$A$2:$D, "select D where A = '"&$C12&"' and B = datetime '"&TEXT(C$1, "yyyy-mm-d hh:mm:ss")&"'"), )), )
The cells with yellow background contain formulae, the ones with green background do not contain formulae but will be auto-populated as the forms get more responses. The single cell with red background (C11), you'll have to write manually ;) Hope this solves your issue!