I am stumped. I have a Timesheet class that holds work days in a dictionary called self.timesheet with dates as the keys and hours, rate as values. I am trying to write a function that can show all the entries in a user defined range of dates.
for now lets assume the key dates are simple integers 20 - 25. i tried this and it didn't do anything at all. no errors, just nothing.
def show_days(self):
date_from = input("From date: ")
date_to = input("To date: ")
t = self.timesheet
for dates in t[date]:
range(date_from, date to)
print(dates)
I can see this doesn't look right , I feel I need *for dates in range(date_from, date_to)* but I can't figure how to get it to loop over the dictionary keys like that.
You need to loop over the range, then check if that key is in the dictionary:
for day in range(date_from, date_to + 1):
if day in t:
print day, t[day]
Note that the values produced by range() do not include the end point, so I used date_to + 1 to ensure it is included anyway.
If your keys are not integers but, say, datetime.date objects, you'll have to construct some kind of loop with datetime.timedelta() to iterate over all dates between two values:
date = date_from = datetime.date(2012, 1, 15)
date_to = datetime.date(2012, 3, 12)
while date <= date_to:
if date in t:
print date, t[date]
date += datetime.timedelta(days=1)
Related
In my cube, I have several measures at the day grain that I'd like to sum at the day grain but average (or take latest) at the month grain or year grain.
Example:
We have a Fact table with Date and number of active subscribers in that day (aka PMC). This is snapshotted per day.
dt
SubscriberCnt
1/1/22
50
1/2/22
55
This works great at the day level. At the month level, we don't want to sum these two values (count = 105) because it doesn't make sense and not accurate.
when someone is looking at month grain, it should look like this - take the latest for the month. (we may change this to do an average instead, management is still deciding)
option 1 - Take latest
Month-Dt
Subscribers
Jan-2022
55
Feb-2022
-
option 2 - Take aveage
Month-Dt
Subscribers
Jan-2022
52
Feb-2022
-
I've not been able to find the right search terms for this but this seems like a common problem.
I added some sample data at the end of a month for testing:
dt
SubscriberCnt
12/30/21
46
12/31/21
48
This formula uses LASTNONBLANKVALUE, which sorts by the first column and provides the latest value that is not blank:
Monthly Subscriber Count = LASTNONBLANKVALUE( 'Table'[dt], SUM('Table'[SubscriberCnt]) )
If you do an AVERAGE, a simple AVERAGE formula will work. If you want an average just for the current month, then try this:
Current Subscriber Count =
VAR _EOM = CLOSINGBALANCEMONTH( SUM('Table'[SubscriberCnt]), DateDim[Date] )
RETURN IF(_EOM <> 0, _EOM, AVERAGE('Table'[SubscriberCnt]) )
But the total row will be misleading, so I would add this so the total row is the latest number:
Current Subscriber Count =
VAR _EOM = CLOSINGBALANCEMONTH( SUM('Table'[SubscriberCnt]), DateDim[Date] ) //Get the number on the last day of the month
VAR _TOT = NOT HASONEVALUE(DateDim[MonthNo]) // Check if this is a total row (more than one month value)
RETURN IF(_TOT, [Monthly Subscriber Count], // For total rows, use the latest nonblank value
IF(_EOM <> 0, _EOM, AVERAGE('Table'[SubscriberCnt]) ) // For month rows, use final day if available, else use the average
)
I have a table that is being joined like so
result: select from table where date within (sd;ed)
where sd and ed span multiple months (like sd:2021.07.01 ed:2021.09.30). The table that I'm querying from has a break if you take more than a month, so to get the result I need, I have to do something like the following:
result: uj(uj(select from table where date within (2021.07.01;2021.07.30);select from table where date within (2021.08.01;2021.08.31));select from table where date within (2021.09.01;2021.09.30))
How can I make this dynamic for any sd and ed? That is, how can I break up time range into first days of months, last days of months, and join them all into one table cleanly? My initial idea was to divide the days in the range x amount of time, to be input by a user, then add the number of days that results to the sd to get frames, but that got messy.
Something like this should chunk it for you:
raze{select from t where date within x}each(first;last)#\:/:d group"m"$d:sd+til 1+ed-sd
Do not use where date.month=x as you had suggested - at least not for historical queries
One option for converting your start and end dates into an iterable list of dates might be:
f:{0N 2#(x,raze -1 0+/:`date$mx+1+til(`month$y)-mx:`month$x),y}
Where x is start date and y is end date.
f[2021.07.14;2022.02.09]
2021.07.14 2021.07.31
2021.08.01 2021.08.31
2021.09.01 2021.09.30
2021.10.01 2021.10.31
2021.11.01 2021.11.30
2021.12.01 2021.12.31
2022.01.01 2022.01.31
2022.02.01 2022.02.09
Then you could run:
{select from t where date within x} each f[sd;ed]
And join the results using raze or (uj/)
Team,
I'm trying to get the last 12 months of financials, using the days as my base, and am getting the the expression yield error. I think it's because they aren't text, but calculated columns.
What is best to add to this? I tried 'value' and that didn't work. I think the isnonblank may work.. or is blank? As there will be blanks returned.
Here's the formula:
Last 12 Mn Amt = (if('LSI DP_JP_HistorySummaryBySiteMaster'[Z - Days]>=-365,'LSI DP_JP_HistorySummaryBySiteMaster'[Z Total Revenue + Rent Revenue],""))
The problem is that the TRUE result returns a different data type than the FALSE result.
Try replacing "" with blank or zero.
Last 12 Mn Amt =
IF (
'LSI DP_JP_HistorySummaryBySiteMaster'[Z - Days] >= -365,
'LSI DP_JP_HistorySummaryBySiteMaster'[Z Total Revenue + Rent Revenue],
BLANK ()
)
Note: Omitting the 3rd argument entirely returns BLANK() as the default behavior.
I have an application collecting credit card data. Before sending the information out to the payment entity I am trying to make sure the information entered is, at least, valid. I already worked out the card number and cvv numbers but I am not so sure about the expiry date. The format I get the info is MMYY. So what I am doing is:
-- Simple function to get current date and times
function getdatetime(tz)
local tz = tz or 'America/New_York';
local luatz = require 'luatz';
local function ts2tt(ts)
return luatz.timetable.new_from_timestamp(ts);
end
local utcnow = luatz.time();
local time_zone = luatz.get_tz(tz);
local datetime_raw = tostring(ts2tt(time_zone:localise(utcnow)));
local year, month, day, hour, min, sec, time_reminder = string.match(datetime_raw, "^(%d%d%d%d)%-(%d%d)%-(%d%d)[Tt](%d%d%.?%d*):(%d%d):(%d%d)()");
return year, month, day, hour, min, sec;
end
local current_year, current_month = getdatetime() -- Get current year/Month
local card_expiry_date = 'YYMM'; -- In the app this actually get a value eg: 2204, 2301, 2010, etc.
local card_exp_year = string.sub(card_expiry_date , 3, 4)
local card_exp_month = string.sub(card_expiry_date , 1, 2)
-- Extract the last two digits of the Year
current_year = string.sub(current_year , 3, 4)
-- Check month is valid
if(card_exp_month < '01' or card_exp_month > '12')then
print("This is not a valid month")
else
-- Check date is this month or after
if((card_exp_year < current_year) or (card_exp_year == current_year and card_exp_month < current_month))then
print("Date cannot be before this month.")
else
print("All is good.")
end
end
I do not know if this is the most elegant solution but it works. However it has a huge bug: it will fail at the end of the century. Since I only know the last two digits of the expiry date year, if a card expires in 2102 for instance and we were in 2099 my logic would wrongly reject the date (02 is less than 99).
I am very aware that me an my simple app will likely not be around by then but it bugs me to leave it like this.
Can anyone please suggest a proper way to do this validation?
Thank you!
Wilmar
Credit cards usually expire within a few years. 3 years is average according to some quick web search. Also the owner of a century only card can be safely assumed to be dead and so is his card account.
So when you get a card with 02 in 2099 there is only one reasonable option.
Calculate two differences and pick the smaller one.
Something like local expiresIn = math.min(math.abs(99-2), math.abs(99-102))
I am trying to create a method that takes user entered month and year and prints out an accurate calendar for the month and year. I am about halfway through but have no idea how to move on.
The guidelines Below in Bold is where i am having issues
Determine the beginning of the next month. Calculate the last day of the month by doing the following: Get the next month date, now get the previous day of that next month. Print the Calendar heading for the full month name and year. Print the header row that contains the abbreviated name of the days of the week. Create an array with a length of 7 and a default value of 4 spaces (" ").
Using the date range from the beginning of the month to the end of the month do the following:
Get the numerical representation of the day of the week using the" %w" formatter and convert to an integer. (This will be the index to the array.)
Use the index to set the day of the month within the array, using the "%d" formatter to get the day of the month.
If index equals 6 OR the date equals the last day of the month, then do the following:
Loop through the array
Print the day of the month
Print a blank line Re-initialize the array so that all values are of 4 spaces
def printMonth(year, month)
now= Date.new(year, month, 1)
a= now >> 1
b= a - 1
puts("Calendar for: #{b.strftime("%B, %Y")}")
puts("")
puts("Sun\tMon\tTue\tWed\tThu\tFri\tSat")
days= Array.new(7," ")
c= b.strftime("%w").to_i
end