I'm trying to create a horizontal, ascending ARRAY of date/times but only including times that I specify (8:00AM-5:00PM). I've tried using NETWORKDAYS.INTL, but that seemed to be more difficult and inevitably, did not render accurate results the way I was doing it (probably incorrectly).
February 1, 2020 8:00AM
February 1, 2020 9:00AM
[all hours in between]
February 1, 2020 4:00PM
February 1, 2020 5:00PM
February 2, 2020 8:00AM
[...]
February 2, 2020 5:00PM
February 3, 2020 8:00AM
I'm able to do the formula for the first day, but I'm stumbling at adding the following days.
Here is what I have at the moment:
=IF(
AND(J2>=$E1+$B1,J2<$E1+$C1),
J2+(1/24),
J2-$C1+$B1
)
J2 = The first date in the array =EOMONTH(TODAY(),-1)+1+[8:00AM]
E1 = First day of the month =EOMONTH(TODAY(),-1)+1
B1 = Start time 8:00AM
C1 = End time 5:00PM
Here is my sheet. My formula is in K2 (currently dragging the formula across the row, but a single formula would be ideal.)
EDIT:
After playing with it and discovering ROUNDDOWN to extract the date, I came up with this:
=IF(
AND(J2>=ROUNDDOWN(J2,0)+$B1,J2<ROUNDDOWN(J2,0)+$C1),
J2+(1/24),
ROUNDDOWN(J2,0)+1+$B1
)
I think this will work based on some other discussions we had. it is an automatically generated array that will show just the date for the past 2 weeks. then the date and time for the upcoming two weeks, then just the date for 2 weeks after that. You'll see the number 42 in the SEQUENCE portion of the formula. this controls the overall number of days that the formula works for. You'll also see TODAY()-14. This is when the array is set to "start".
=ARRAYFORMULA(TRANSPOSE(TODAY()-14+QUERY(SEQUENCE(42*24,1,0)/24,"where (Col1 % 1=0 and Col1<14) or (Col1 % 1=0 and Col1>=28) or (Col1 % 1<="&N(C1+0.000001)&" and Col1 % 1>="&N(B1)&" and Col1>=14 and Col1<29)",0)))
try:
=ARRAYFORMULA(E1-1+
SPLIT(QUERY(TRANSPOSE(REPT(TRANSPOSE(ROW(INDIRECT("A1:A"&
DAYS(EOMONTH(E1, 3), E1))))&" ",
HOUR(C1)-HOUR(B1)+1)),,9^9), " ")+
SPLIT(REPT(QUERY((ROW(INDIRECT("A1:A"&
HOUR(C1)-HOUR(B1)+1))+HOUR(B1)-1)/24&" ",,9^9),
DAYS(EOMONTH(E1, 3), E1)), " "))
to change span from 3 months to one replace those two 3 for two 1
shorter, faster, lightweight mathematical solution:
=ARRAYFORMULA(SPLIT(QUERY(TRANSPOSE(QUERY(TRANSPOSE(ARRAY_CONSTRAIN(
N(E1)+SEQUENCE(DAYS(EOMONTH(E1, D1-1), E1), 24, HOUR(B1))/24,9^9,
1+HOUR(C1)-HOUR(B1))),,9^9)),,9^9), " "))
While this does solve my overall problem, it's not the ultimate formula I'm seeking which would be a single ARRAYFORMULA.
=IF(
AND(J2>=ROUNDDOWN(J2,0)+$B1,J2<ROUNDDOWN(J2,0)+$C1),
J2+(1/24),
ROUNDDOWN(J2,0)+1+$B1
)
#MattKing solution:
=ARRAYFORMULA(TRANSPOSE(EOMONTH(TODAY(),-1)+1+QUERY(MOD(
SEQUENCE(SUM({-1,1}*EOMONTH(TODAY(),{-1,D1}))*24,1,0)/24,{9^99,1}),
"select Col1 where Col2<="&N(C1+0.000001)&" and Col2>="&N(B1),0)))
Related
I am comparing two dates in SQL Server and need following information in precise manner:
Input:
Start Date = 12/28/2015
End Date = 12/25/2020
Result returned (each piece in different column):
Days = 1825 (includes start/end date in calculation)
Years = 4
Months = 11
Days = 28
How many days in Start Month = 31 days (Because it is December)
Occupancy in Start Month = (because December has 31 days, it would be 4/31) = .12903225806
How many days in End Month = 31 days (Because it is December)
Occupancy in End Month = (because December has 31 days, it would be 25/31) = .8064516129
For 1-3, you can check https://www.w3schools.com/sql/func_sqlserver_datediff.asp. It's fairly simple, you can just use datediff and specify the unit of interest.
For 4, you can simply do day(Start Date) to get the date.
For 5 and 7, you can use:
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#myDate)+1,0)
to get the end of month date of the given date and use day() to get the day part of the datetime object.
For 6 and 8, it's just simple math, you get number of month in that month from 5 and 7, and then, if Start Date, then (day(eom(Start Date)) - day(Start Date) + 1) / day(eom(date) and if End Date, then day(End Date) / day(eom(End Date)).
I didn't give you the full code as I don't have SQL server running besides me. Hope it helps.
I have a table like this:
Year Month Code Amount
---------------------------------------
2017 11 a 7368
2017 11 b 3542
2017 12 a 4552
2017 12 b 7541
2018 1 a 6352
2018 1 b 8376
2018 2 a 1287
2018 2 b 3625
I make slicer base on Year and Month (ignore the Code), and I want to show SUM of Amount like this :
If I select on slicer Year 2017 and Month 12, the value to be shown is SUM Amount base on 2017-11, and select on slicer Year 2018 and Month 1 should be SUM Amount base on 2017-12
I have tried this one for testing with, but this not allowed:
Last Month = CALCULATE(SUM(Table[Amount]); Table[Month] = SELECTEDVALUE(Table[Month]) - 1)
How to do it right?
I want something like this
NB: I use direct query to SQL Server
Update: At this far, I added Last_Amount column in SQL Server Table by sub-query, maybe you guys have a better way for my issue
The filters in a CALCULATE statement are only designed to take simple statements that don't have further calculations involved. There are a couple of possible remedies.
1. Use a variable to compute the previous month number before you use it in the CALCULATE function.
Last Month =
VAR PrevMonth = SELECTEDVALUE(Table[Month]) - 1
RETURN CALCULATE(SUM(Table[Amount]), Table[Month] = PrevMonth)
2. Use a FILTER() function. This is an iterator that allows more complex filtering.
Last Month = CALCULATE(SUM(Table[Amount]),
FILTER(ALL(Table),
Table[Month] = SELECTEDVALUE(Table[Month]) - 1))
Edit: Since you are using year and month, you need to have a special case for January.
Last Month =
VAR MonthFilter = MOD(SELECTEDVALUE(Table[Month]) - 2, 12) + 1
VAR YearFilter = IF(PrevMonth = 12,
SELECTEDVALUE(Table[Year]) - 1,
SELECTEDVALUE(Table[Year]))
RETURN CALCULATE(SUM(Table[Amount]),
Table[Month] = MonthFilter,
Table[Year] = YearFilter)
I need to check if a Date is between 1st of 1st month and 29th of 7th month of any year.
Before going ahead and hacking extracting Month Day from the date and comparing it to being between 0101 and 0729 (or just checking if the date dd mm is less than 629) type of hideousity solution, I must ask is there a function to check wether any date falls in between particalr days and month , invariant of the it's year.
Other wise extracting months and days from the date and doing some hacky arithmatic is easy, but I want to be leave a better code for the poor programmer who will come after me and not having to guess why the hell some freaky made up arithmatic is going on, I rather be explicit even if it takes longer.
Another option:
DECLARE #TheDate date = '2016-07-29';
SELECT 1
WHERE DATEADD(Year, -(YEAR(#TheDate) - 2000), #TheDate)
BETWEEN '2000-01-01' AND '2000-07-29'
where datetimeField < dateFromParts( year( dateTimeField ), 7, 30)
EDIT: Above would work in 2012 and later. For 2008 you could do some arithmetic which is "very simple" for a developer:
where datetimeField < CAST(CAST(year(dateTimeField) AS CHAR(4))+'0730' AS DATE);
Or simplified a bit:
where datetimeField < CAST(year(dateTimeField) AS CHAR(4))+'0730';
PS: A common pitfall in using BETWEEN (which acts like x >= v1 and x <= v2) on a datetime field, where the field might have time part, is not suggested and would never help to precisely get the correct records (because there is no way to specify the ending time). Instead you should always use x >= v1 and x < v2 style where v2 is the minimum exclusive upper value. ie: To get all the sales in May 2000 (saleDate has time component):
saleDate >= '20000501' and saleDate < '20000601'
NOT:
saleDate between '20000501' and '20000531'
OR NOT:
saleDate >= '20000501' and saleDate <= '20000531'
Select * from TableWithNoName where DateField1 between DATETIMEFROMPARTS( YEAR(DateField1),1, 1, 0, 0, 0, 0 ) and DATETIMEFROMPARTS( YEAR(DateField1),7, 29, 23, 59, 59, 999 )
assuming DateField1 is a Date Value
I put several data (Names, dates, times and values) into an array. It goes wrong with the date and time.
Where do I go wrong? Here is a piece of my code:
For i = 1 To LastRow + 13
For j = 1 To 10
strArray(i, j) = Cells(i, j).Value2
Next j
Next i
So 0,000983796 should become 0:01:25.
In Excel, a date is the number of days since January 1, 1900 starting
with January 1, 1900 being “1”. Each date after that, Excel adds one
more number to that sequence. So August 26, 2013 is 41512, or 41,512
days since January 1, 1900.
The integer part of the number is used for the days. The decimal part
of the number is the fractional part of the day — or the time. So .5
would be 50% of the way thru the day, or 12:00 noon. That makes
41,512.5 to be equivalent to 12:00 noon on August 26, 2013.
From DATE VALUES IN EXCEL EXPLAINED
You can convert this number value back into something more pretty and readable.
dim pretty as String
pretty = Format(Cells(i, j).Value2, "h:mm:ss")
More examples on vba formatting
I am working on a report in Microsoft SQL Server Report Builder and I am trying to write an expression that will display only the next 5 business days from today (i.e. a table has 5 columns and it starts from today and proceeds for the next five business days). If the day is a Saturday or Sunday, which using my enumeration value would return a 6 or a 7 using the Weekday function, you would skip ahead to the next business day. Currently I have this expression for the first column after the column with today's date
IIf(Weekday(DateAdd("d",1,Today()),2)=6,DateAdd("d",3,Today()),
(IIf(Weekday(DateAdd("d",1,Today()),2)=7,DateAdd("d",2,Today()),
DateAdd("d",1,Today()))))
and it doesn't work. I believe this is because if we have a day like Wednesday, Thursday, or Friday, not enough days are being skipped over for the weekend days.
If we can assume that you are going to start from a business day then there is a simple formula we can use:
=IIF(6 - WeekDay(Today()) - X < 0, DateAdd("d", X + 2, Today()), DateAdd("d", X, Today()))
where X is the number of days that column is from the start date.
Unfortunately, it breaks down if the start date is a Saturday or Sunday but if you only need it for business days then you are good to go.
I think you have to use previous column value instead of using Today()
So inthe first column it will be the current date. (Apply the same formula if it can start from weekend days).
I think switch case is more easy in this condition.
Formula for current day column
=switch (
Weekday(today) = 6, dateadd("d", 2, today),
Weekday(today) = 7, dateadd("d", 1, today),
Weekday(today) < 6, today
)
In the second column instead of today() use "Fields!previous_column_name.Value".
=switch (
Weekday(dateadd("d", 1, Fields!previous_column_name.Value)) = 6, dateadd("d", 3, Fields!previous_column_name.Value),
Weekday(dateadd("d", 1, Fields!previous_column_name.Value)) = 7, dateadd("d", 2, Fields!previous_column_name.Value),
Weekday(dateadd("d", 1, Fields!previous_column_name.Value)) < 6, dateadd("d", 1, Fields!previous_column_name.Value)
)
In third column use the second column as previous_column.
Hope this will help you.