I have a zap # Zapier which automatically imports my Strava activity to Google Sheets. This works fine, but it inputs everything as text. I want to be able to calculate my running (accumulated) average pace, but it is not possible with the data as is. So, do any of you have any formulaes for converting the info in column G to proper google sheets time format so that I can use it for calculations?
Here is a link to the data: https://docs.google.com/spreadsheets/d/1UD25--vrVgVp0AuhLFi7CGWFIo-GHeLfD_n8WqDbNrE/edit?usp=sharing
Try this formula in any blank column on row 2.
=(value(left(G2;len(G2)-3)) + value(right(G2;2))/60)/60/24
This parses the time value, eg 2:34, in column G, extracting the minutes from in front of the colon, and the seconds from after the colon, converts them from text to numbers, adds them together, and divides by 60 to get hours, and by 24 to get fractions of a day. Is this what you want?
For a formula that will do the whole column, place the following in row 1 of a blank column, and format the column for Time:
={"Time";arrayformula((value(left(G2:G;len(G2:G)-3)) + value(right(G2:G;2))/60)/60/24)}
Let me know if you need something else.
Related
I am trying to record the time it takes for a number of things to occur, and can't seem to get Google Sheets to understand my input. I want to be able to type something like "26:30" into a cell, and have the spreadsheet understand that this means 26 minutes and 30 seconds, and then be able to use that number in formulas, e.g. to return the shortest of a series of times, or the difference between two times.
Also, the vast majority of the numbers I type in will be under an hour, so I don't want to have to type in something like "0:26:30" every time, just for it to understand that I mean 26 minutes, not 26 hours. However for the rare occasions where something is longer than an hour, I want to be able to be able to type something like "1:10:23" and not "70:23".
If possible, I would rather achieve this through directly formatting the cell I type the time into, rather than enter it in one format and have it converted in a separate cell via a formula.
Is there a way to do this that meets all of these goals?
google sheets is not designed in such a way. if you want to type in 26:30 then the best course of action is as follows:
convert cells to Plain Text, type in your duration, and account for your rules within formulae. to convert a text string into a value for the sake of calculation you can use the following principle
=ARRAYFORMULA(IFERROR(IF(REGEXMATCH(A1:A, ":\d+:"), A1:A*1, ("0:"&A1:A)*1)))
few examples:
=ARRAYFORMULA(TEXT(AVERAGE(IF(REGEXMATCH(A1:A2, ":\d+:"),
A1:A2*1, ("0:"&A1:A2)*1)), "[m]:ss"))
=ARRAYFORMULA(TEXT(SUM(IF(REGEXMATCH(A1:A2, ":\d+:"),
A1:A2*1, ("0:"&A1:A2)*1)), "[h]:mm:ss"))
=ARRAYFORMULA(TEXT(IF(REGEXMATCH(A2, ":\d+:"), A2*1, ("0:"&A2)*1)-
IF(REGEXMATCH(A1, ":\d+:"), A1*1, ("0:"&A1)*1), "[m]:ss"))
At this point in time there doesn't seem to be a way to directly format a cell such that Google Sheets recognises it as MM:SS instead of HH:MM, so I've had to go with formulas instead. Sharing the solution I used below.
I set it up so that the user entered the time into cell A1 in the form MM:SS or H:MM:SS and I formatted this cell as plain text, then had a second cell formatted as 'time duration' where it converted the input of A1 using the following formula:
=time(left(A1,if(len(A1)<6,"",len(A1)-6)),right(left(A1,len(A1)-3),2),right(A1,2))
To break this down:
It starts by assuming the contents of A1 is a text string with 5 or more characters in the form MM:SS or H:MM:SS or HH:MM:SS. It does not include any sort of error handling to check this is true.
The time(X,Y,Z) part of the formula converts different inputs into hours, minutes and seconds, respectively, and produces a number in the format HH:MM:SS, which is recognised as a time, and can therefore be used in formulas. Note that the cell has to be formatted as 'time duration' to display correctly.
In the above, Z is right(A1,2) which extracts the last two characters of A1, i.e. the SS part of the input. These end up as seconds.
Likewise, Y is right(left(A1,len(A1)-3),2) which extracts the 4th and 5th characters from the right of the text string of A1, i.e. the MM part of the input, after the :. This number is then recognised as minutes.
Finally, X is left(A1,if(len(A1)<6,"",len(A1)-6)), which basically says "if A1 is less than 6 characters then it must not have hours, so leave blank, otherwise extract out all characters except the last 6", i.e. the HH part of the input, if it exists. This number (which may or may not be 0) is then recognised as hours.
I can't figure out how to solve my issue in google spreadsheet.
I have a column with some packages we want to release on our website on specific random dates. Not all fields in these column are populated, some are empty. For the populated ones I want to assign a random number between a range (A,B) which I take from other fields and have a max number of duplicates (the number of duplicates I take from another field).
For example I have 60 packages and I need to assign them between 1 and 31 (days of current month) so that means I will have 2 duplicates/day and I will put my duplicate field value to 2. But these 60 packages are shown in 80 rows for example, 20 rows empty, so those must not have any number assigned to them.
I have tried a few solutions with RANDBETWEEN and SORT etc but I did not manage to make it work. Now I switched to writing a custom function but I have never written one in google app scripts before, so if any of you guys have experience with this I would highly appreciate.
Random dates
Use this formula to get random dates between start date and end date appended randomly and duplicated only twice.
=ArrayFormula(IF(A2:A="",,
VLOOKUP(A2:A,
{SORT({ FILTER(A2:A,A2:A<>""),
RANDARRAY(COUNTA( FILTER(A2:A,A2:A<>"")),1) },2,1),
TRANSPOSE(SPLIT(REPT(TEXTJOIN(";",1,($E$1+SEQUENCE(DATEDIF($E$1,$E$2,"D"),1,1)))&";",$E$5),";"))},3,0)))
Sort chronologically
01 - paste in G2.
=SORT(QUERY(UNIQUE(QUERY({B2:B},"Select * where Col1 is not null ")), "where Col1 is not null"),1,1)
02 - paste this formula in H2 and drag down.
=IF(G2="",,TEXTJOIN(", ",1,FILTER($A$2:$A,$B$2:$B=G2)))
I have a sheet with a timeline that shows a month per row in column A and an amount in USD next to that month in column B.
I want to be able to specify amounts in column G with a start and end date for that amount in columns E and F.
What I am trying to achieve is that the values in column B are automatically calculated by looking at the start and end dates specified in columns E and F and then taking the corresponding value from column G if the date in column A falls in between the date range specified in E and F.
I have found many suggestions for similar problems online but wasn't able to get any of them to work for my specific case. Any help is very welcome
You could do it as an array formula like this:
=ArrayFormula(mmult((text(indirect("A2:A"&count(A2:A)+1),"YYMM")>=text(TRANSPOSE(indirect("`E3:E"&count(E3:E)+2)),"YYMM"))*(text(indirect("A2:A"&count(A2:A)+1),"YYMM")<=text(transpose(indirect("F3:F"&count(F3:F)+2)),"YYMM"))*transpose(indirect("G3:G"&count(G3:G)+2)),(INDIRECT("G3:G"&count(G3:G)+2)+2)^0))
The idea is to develop a 2D array where the rows are the months and the columns are the amounts for matching time periods. Then use the standard Mmult method to get the row totals of the array.
Using indirect for the ranges makes the formula longer but using full-column references would be slow as it would result in a nearly 1000 X 1000 array for a default-sized sheet.
EDIT 1
Or shorter
=ArrayFormula(mmult((text(indirect("A2:A"&count(A2:A)+1),"YYMM")>=text(TRANSPOSE(indirect("E3:E"&count(E3:E)+2)),"YYMM"))
*(text(indirect("A2:A"&count(A2:A)+1),"YYMM")<=text(transpose(indirect("F3:F"&count(F3:F)+2)),"YYMM"))
,INDIRECT("G3:G"&count(G3:G)+2)))
because you can combine the row totals step with multiplication by column G.
EDIT 2
Alternatively you could just employ a much simpler pull-down formula using SUMIFS:
=ArrayFormula(sumifs(G$3:G,eomonth(E$3:E,-1)+1,"<="&A2,F$3:F,">="&A2))
This uses Eomonth to change all the start dates to the first of the month so they can be compared to the dates in column A correctly. The formula still has to be entered as an array formula because of the Eomonth calculation.
Note
The equivalent pull-down formula to the original array formulas above would be
=ArrayFormula(sumifs(G$3:G,text(E$3:E,"YYMM"),"<="&text(A2,"YYMM"),text(F$3:F,"YYMM"),">="&text(A2,"YYMM")))
but this gives zero for all rows - the reason for this is not obvious to me at time of writing.
I'm using Google Sheets to create a financial record.
What i'm trying to do is create a formula that takes 3 columns in my data range in to consideration. The three columns are a date, a word and a number.
The first part of the formula will check that the date is the current month (not within 30 days, but the current month). The second part will check whether the word "Yes" is present in the second column, and if those two are true, then it will take the average of column 3 for all other rows that are also completely true.
Column C is Date
Column W is Word
Column Y is Number
I've tried a number of methods, the first one was to use a average IF function, where i used a filter to check the dates, and then the word Yes in the criterion. This resulted in a number, although it was incorrect, as the formula first gathered the sequence of Yes and No's, once it had the sequence it applied it to the third column but it started from my earliest entry (not my current month). This code is below.
So alternatively i tried another method. Which was using a query function. Although i'm stuck on how to compare the month of a date to the current today() month. This gives no results, even though the current month is 8, and the dates month is also 8. I've also inputted this code below.
=AVERAGEIF(filter(W8:W800,month(C8:C800)=month(today())),"Yes",Y8:Y800)
=query(query(A8:Z800,"select month(C)+1, W, Y where W ='Yes'",0),"select Col1, Col3, Col4 where Col1 ='"&month(today())&"'",1)
results explained in background
Your nesting is a bit off. If you're using FILTER, use plain AVERAGE instead of AVERAGEIF, and make sure you're grabbing the right column to aggregate. Lastly, don't forget to wrap in IFERROR to handle your empty case.
=IFERROR(AVERAGE(FILTER(Y8:Y800, MONTH(C8:C800)=MONTH(TODAY()), W8:W800="Yes")), 0)
if you have multiple criterions you need to use AVERAGEIFS instead of AVERAGEIF
=ARRAYFORMULA(AVERAGEIFS(C2:C, B2:B, "yes", MONTH(A2:A), MONTH(TODAY())))
I have 5 columns of numbers that I want to sort per row into another set of columns. I figured I need to use small() (e.g. small(a2:e2,1) for f2; small(a2:e2,2) for g2 and so on). Is there away to iterate this for the next rows; if possible using only native google spreadsheet formulas?
Thanks in advance
I was able to make a temporary work around, but I had to use 3 cheat columns. It looks ok for now but I imagine it will be troublesome for really huge numbers.
Here's a sample sheet for reference: https://docs.google.com/spreadsheets/d/1MQTP2XkRsPRAnPQ5wLhkR8JoNVY6YOExVlOkkX8UeRs/edit#gid=0
The original data are in A3:E
The first cheat column (G3:G) simply creates a column of numbers from 1 to the largest number found in the source data. 1-9 is changed to 01-09 for easier searching. "#" is then added at the end-this will come handy later:
Cheat Column 1 =filter(if(row(A:A)=max(A:E)+1,ʺ#ʺ,text(row(A:A),ʺ00ʺ)),row(A:A)<=max(A:E)+1)
The second cheat column (H3:H) combines each row into a string separated by "-" with a "#" marker:
Cheat Column 2=filter(text(A3:A,ʺ00ʺ)&ʺ-ʺ&text(B3:B,ʺ00ʺ)&ʺ-ʺ&text(C3:C,ʺ00ʺ)&ʺ-ʺ&text(D3:D,ʺ00ʺ)&ʺ-ʺ&text(E3:E,ʺ00ʺ)&ʺ#ʺ,A3:A<>ʺʺ)
The last cheat column (I3:I) sorts each line (from cheat column 2) by finding each number from cheat column from 01 up to the max number, then the "#" char (this ensures that each line will still have the # end marker). "Find" will return the "position" of each number or an error if it's not found. By using "if", we can make "find" return the actual number or "" instead.
=filter(arrayformula(if(iferror(find(transpose(filter(G3:G,G3:G<>ʺʺ)),H3:H),ʺʺ), transpose(filter(G3:G,G3:G<>ʺʺ)),ʺʺ)),A3:A<>ʺʺ)
The formula above creates as many columns as there are numbers from cheat column 1. To prevent this, a "-" is added to each number then "Concatenate" is used to combine everything into one massive string with each set separated by "#". The string is then split using the "#" marker.
Cheat Column 3 =transpose(split(concatenate(filter(arrayformula(if(iferror(find(transpose(filter(G3:G,G3:G<>ʺʺ)),H3:H),ʺʺ),ʺ-ʺ&transpose(filter(G3:G,G3:G<>ʺʺ)),ʺʺ)),A3:A<>ʺʺ)),ʺ#ʺ))
Each number is then separated into each corresponding column by using mid().
Small 1 =filter(mid(I3:I,2,2)*1,A3:A<>ʺʺ)
Small 2 =filter(mid(I3:I,5,2)*1,A3:A<>ʺʺ)
Small 3 =filter(mid(I3:I,8,2)*1,A3:A<>ʺʺ)
Small 4 =filter(mid(I3:I,11,2)*1,A3:A<>ʺʺ)
Small 5 =filter(mid(I3:I,14,2)*1,A3:A<>ʺʺ)
Note that the formula above is only for numbers 1-99. For larger numbers, the Text() formulas should have more zeroes to correspond to the number of digits of the biggest number. The Mid() formulas should also be adjusted accordingly.
I would like to stress that I am very far from being a spreadsheet expert and that this solution is very "unoptimized". It requires several cheat columns; with the first one even having more rows than the original data. If anyone can help me get rid of the cheat columns (or at least the first one) I will be very grateful.
How about using SMALL like you mentioned in your question?
=small($A3:$E3,column()-columns($A3:$G3))
You will need to change the ranges accordingly. The last $G$3 is the cell just before the cell where the formula is placed.
Sample