Generate calendar Python webpage - python

Re-phrasing my Question, as suggested by moderator.
I need to create a calendar with Python & CSS for a web page, I tried the following in Python:
#!/usr/bin/env python
import os, re, sys, calendar
from datetime import datetime
myCal = calendar.monthcalendar(2011,9)
html += str(myCal)
mycal = myCal[:1]
cal1 = myCal[1:2]
cal2 = myCal[2:3]
cal3 = myCal[3:4]
cal4 = myCal[4:5]
html += str(mycal)+'<br>'
html += str(cal1)+'<br>'
html += str(cal2)+'<br>'
html += str(cal3)+'<br>'
html += str(cal4)+'<br>'
html += "<br>"
This is the following output on the web page:
[[0, 0, 0, 1, 2, 3, 4]]<br>
[[5, 6, 7, 8, 9, 10, 11]]<br>
[[12, 13, 14, 15, 16, 17, 18]]<br>
[[19, 20, 21, 22, 23, 24, 25]]<br>
[[26, 27, 28, 29, 30, 0, 0]]<br>
How can I arrange the above in the following format below?
(
This is a SAMPLE format, I have not done the actual Day / Date match.
The format needs to be in TWO rows.
eg.DayDateimgNDayDateimgN next month
)
Dec , 2011
----------------------------------------------------------------------------
sun | mon | tue | wed thu fri sat sun mon tue wed thu fri sat sun
-------|-------|-------|----------------------------------------------------
.... 1 |.. 2 ..|.. 3 ..| 4 5 6 7 8 9 10 11 12 13 14 15<br>
------ |-------|-------|----------------------------------------------------
img1 | img2 | img3 | ....
Jan , 2012
----------------------------------------------------------------------------
sun | mon | tue | wed thu fri sat sun mon tue wed thu fri sat sun
-------|-------|-------|----------------------------------------------------
.... 1 |.. 2 ..|.. 3 ..| 4 5 6 7 8 9 10 11 12 13 14 15<br>
------ |-------|-------|----------------------------------------------------
img1 | img2 | img3 | ....
Feb , 2012
----------------------------------------------------------------------------
sun | mon | tue | wed thu fri sat sun mon tue wed thu fri sat sun
-------|-------|-------|----------------------------------------------------
.... 1 |.. 2 ..|.. 3 ..| 4 5 6 7 8 9 10 11 12 13 14 15<br>
------ |-------|-------|----------------------------------------------------
img1 | img2 | img3 | ....

I'm not sure exactly what you are looking for, this produces a table with the 3 rows you describe, but for the entire month (not just the first 15 days). I may be starting point
import calendar
import itertools
blank = " "
myCal = calendar.monthcalendar(2011,9)
day_names = itertools.cycle(['mon','tue','wed','thu','fri','sat','sun']) # endless list
cal = [day for week in myCal for day in week] # flatten list of lists
# empty lists to hold the data
headers = []
numbers = []
imgs = []
# fill lists
for d in cal:
if d != 0:
headers.append(day_names.next())
numbers.append(d)
imgs.append("image"+str(d))
else:
headers.append(day_names.next())
numbers.append(blank)
imgs.append(blank)
# format data
html = "<table><tr></tr>{0}<tr>{1}</tr><tr>{2}</tr></table>".format(
"".join(["<td>%s</td>"% h for h in headers]),
"".join(["<td>%s</td>"% n for n in numbers]),
"".join(["<td>%s</td>"% i for i in imgs]))

I'm not quiet sure I understand the exact format your wanting but you can put the calender into a table of 3 rows.
Try this for each of your months
import calendar
myCal = calendar.monthcalendar(2011,9)
#make multi rowed month into a single row list
days = list()
for x in myCal:
days.extend(x)
#match this up with the week names with enough weeks to cover the month
weeks = len(myCal) * ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
#some images
images = ['image1', 'image2', '...']
#make sure there is at least a zero at the end of the list
days.append(0)
#find start and end indexes where the actual day numbers lie
start_index = days.index(1)
#if there are no zeros at the end of the list this will fail
end_index = days[start_index:].index(0) + len(days) - len(days[start_index:])
header = 'Dec, 2011'
#Create the table rows of just the items between start_index and end_index.
weekday_row = '<tr>%s</tr>'%(''.join(['<td>%s</td>'%(x)
for x in weeks[start_index:end_index]]))
day_row = '<tr>%s</tr>'%(''.join(['<td>%d</td>'%(x)
for x in days[start_index:end_index]]))
image_row = '<tr>%s</tr>'%(''.join(['<td>%s</td>' % (x) for x in images]))
#finally put them all together to form your month block
html = '<div>%s</div><table>\n\n%s\n\n%s\n\n%s</table>' % (header,
weekday_row,
day_row,
image_row)
You can repeat that as many times as you need

Related

How to find the time to iterate over two array?

The function is passed a dictionary containing three lists with timestamps (time in seconds):
lesson - the beginning and end of the lesson
pupil - intervals of pupil presence
tutor - intervals of the teacher's presence
The intervals are arranged as follows - it is always a list of an even number of items. Even indices (starting from 0) are the time of entry to the lesson, and odd ones are the time of leaving the lesson.
How can I calculate the time when both student and teacher are present in class at the same time? That is, the time of their crossing
dc = {
'lesson': [1594663200, 1594666800],
'pupil': [1594663340, 1594663389, 1594663390, 1594663395, 1594663396, 1594666472],
'tutor': [1594663290, 1594663430, 1594663443, 1594666473]}
My solution, I could only calculate the total time spent by each
lesson_times = dc['lesson']
pupil_times = dc['pupil']
tutor_times = dc['tutor']
total_time_pupil = 0
start_time_pupil = 0
end_time_pupil = 0
if len(pupil_times) > len(tutor_times):
for index, times in pupil_times
for index, time in enumerate(pupil_times):
if (index % 2) == 0:
start_time_pupil = time
else:
end_time_pupil = time
if start_time_pupil != 0 and end_time_pupil !=0:
total_time_pupil += (end_time_pupil - start_time_pupil)
start_time_pupil = 0
end_time_pupil = 0
tutor_times = dc['tutor']
total_time_tutor = 0
start_time_tutor = 0
end_time_tutor = 0
for index, time in enumerate(tutor_times):
if (index % 2) == 0:
start_time_tutor = time
else:
end_time_tutor = time
if start_time_tutor != 0 and end_time_tutor != 0:
total_time_tutor += (end_time_tutor - start_time_tutor)
start_time_tutor = 0
end_time_tutor = 0
I had written this when you posted the first time. This solves your problem.
import time
dc = {
'lesson': [1594663200, 1594666800],
'pupil': [1594663340, 1594663389, 1594663390, 1594663395, 1594663396, 1594666472],
'tutor': [1594663290, 1594663430, 1594663443, 1594666473]}
puptimes = dc['pupil'][:]
tuttimes = dc['tutor'][:]
pupil_in = False
tutor_in = False
last = 0
together = 0
while puptimes and tuttimes:
# Pick the event to come next.
if puptimes[0] < tuttimes[0]:
evt = puptimes.pop(0)
pupil_in = not pupil_in
else:
evt = tuttimes.pop(0)
tutor_in = not tutor_in
tc = time.ctime(evt)
if pupil_in and tutor_in:
print( tc, "Both are in the room." )
last = evt
else:
if last:
print( tc, "No longer both in, together time =", evt-last )
together += evt-last
last = 0
if pupil_in:
print( tc, "Pupil is in the room alone" )
elif tutor_in:
print( tc, "Tutor is in the room alone" )
else:
print( tc, "Room is empty" )
print( "Total time together:", together, "seconds" )
Output:
[timr#Tims-Pro:~/src]$ python x.py
Mon Jul 13 11:01:30 2020 Tutor is in the room alone
Mon Jul 13 11:02:20 2020 Both are in the room.
Mon Jul 13 11:03:09 2020 No longer both in, together time = 49
Mon Jul 13 11:03:09 2020 Tutor is in the room alone
Mon Jul 13 11:03:10 2020 Both are in the room.
Mon Jul 13 11:03:15 2020 No longer both in, together time = 5
Mon Jul 13 11:03:15 2020 Tutor is in the room alone
Mon Jul 13 11:03:16 2020 Both are in the room.
Mon Jul 13 11:03:50 2020 No longer both in, together time = 34
Mon Jul 13 11:03:50 2020 Pupil is in the room alone
Mon Jul 13 11:04:03 2020 Both are in the room.
Mon Jul 13 11:54:32 2020 No longer both in, together time = 3029
Mon Jul 13 11:54:32 2020 Tutor is in the room alone
Total time together: 3117 seconds
[timr#Tims-Pro:~/src]$

Calculate previous occurence

df month order customer
0 Jan yes 020
1 Feb yes 041
2 April no 020
3 May no 020
Is there a way to calculate the last month a customer ordered if order = no? Expected Output
df month order customer last_order
0 Jan yes 020
1 Feb yes 041
2 April no 020 Jan
3 May no 020 Jan
You can df.groupby, and pd.Series.eq to check if value is yes, then use pd.Series.where and use pd.Series.ffill, then mask using pd.Series.mask
def func(s):
m = s['order'].eq('yes')
f = s['month'].where(m).ffill()
return f.mask(m)
df['last_order'] = df.groupby('customer', group_keys=False).apply(func)
month order customer last_order
0 Jan yes 020 NaN
1 Feb yes 041 NaN
2 March no 020 Jan
Explanation
What happens in each of the group after groupby is the below, for example consider group where customer is 020
month order
0 jan yes
1 apr no
2 may no
3 jun yes
4 jul no
m = df['order'].eq('yes') # True where `order` is 'yes'
f = df['month'].where(m)#.ffill()
f
0 jan # ---> \
1 NaN \ #`jan` and `jun` are visible as
2 NaN / # they were the months with `order` 'yes'
3 jun # ---> /
4 NaN
Name: month, dtype: object
# If you chain the above with with `ffill` it would fill the NaN values.
f = df['month'].where(m).ffill()
f
0 jan
1 jan # filled with valid above value i.e Jan
2 jan # filled with valid above value i.e Jan
3 jun
4 jun # filled with valid above value i.e Jun
Name: month, dtype: object
f.mask(m) # works opposite of `pd.Series.where`
0 NaN # --->\
1 jan \ # Marked values `NaN` where order was `yes`.
2 jan /
3 NaN # --->/
4 jun
Name: month, dtype: object
You might do it with df.iterrows:
df = pd.DataFrame([{'month': 'Jan', 'order': 'yes', 'customer': '020', 'month_2': 1, 'last_order': None},
{'month': 'Feb', 'order': 'yes', 'customer': '041', 'month_2': 2, 'last_order': None},
{'month': 'April', 'order': 'no', 'customer': '020', 'month_2': 4, 'last_order': 'Jan'},
{'month': 'May', 'order': 'no', 'customer': '020', 'month_2': 5, 'last_order': 'Jan'}])
#Lets convert months to numeric value
dict_months = dict(Jan=1, Feb=2, March=3, April = 4,May=5, June = 6,Jul = 7, Aug = 8, Sep = 9, Oct = 10, Nov =11, Dec = 12)
df['month_2'] = df.month.map(dict_months)
#Insert a blank column for last_order
df['last_order'] = None
#Let's iter throught rows
for idx, row in df.iterrows():
if row['order'] == "yes": continue
#For each row, grab the customer and the current month and searchfor orders in previous months
df_temp = df[(df.customer == row['customer']) & (df.month_2 < row['month_2'] )& (df.order == "yes")]
#If any result found, let pick the last know order and update accordingly the DataFrame
if df_temp.shape[0]>0: df.loc[[idx],'last_order'] = df_temp['month'].iloc[-1]
#remove unecessary column
del df['month_2']
Output
| month | order | customer | last_order |
|:--------|:--------|-----------:|:-------------|
| Jan | yes | 020 | |
| Feb | yes | 041 | |
| April | no | 020 | Jan |
| May | no | 020 | Jan |

Print a calendar starting from today's date

I want to print a calendar of the current month but starting from today's date in python. Is there any way I can do this?
Only thing I thought to try was :
import calendar
y = int(input("Input the year : "))
m = int(input("Input the month : "))
d = int (input("Input the day: "))
print(calendar.month(y, m, d))
which in retrospect is a dumb idea because all it did was :
but considering my 3 day experience in python it seemed dumb enough to work.
I want the end result to look something like this:
Essentially,I want the calendar to show only the remaining days of the month,instead of the whole month.
The calender method returns a string. You can use conventual string manipulation methods to modify the string before printing - f.e. regex replacement:
import calendar
import re
y = 2020
m = 5
d = 15
h = calendar.month(y, m, 3) # 3 is the width of the date column, not the day-date
print(h)
print()
# replace all numbers before your day, take care of either spaces or following \n
for day in range(d):
# replace numbers at the start of a line
pattern = rf"\n{day} "
h = re.sub(pattern, "\n " if day < 10 else "\n ", h)
# replace numbers in the middle of a line
pattern = rf" {day} "
h = re.sub(pattern, " " if day < 10 else " ", h)
# replace numbers at the end of a line
pattern = rf" {day}\n"
h = re.sub(pattern, " \n" if day < 10 else " \n", h)
print(h)
Output:
May 2020
Mon Tue Wed Thu Fri Sat Sun
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
# after replacement
May 2020
Mon Tue Wed Thu Fri Sat Sun
15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

How can i convert this string to integers & other strings in Python

I got this string...
String = '-268 14 7 19 - Fri Aug 3 12:32:08 2018\n'
I want to get the first 4 numbers (-268, 14, 7, 19) in integer-variables and Fri Aug 3 12:32:08 in another string-variable.
Is that possible?
Using basic python
string = '-268 14 7 19 - Fri Aug 3 12:32:08 2018\n'
vals, date = string.strip().split(' - ')
int_vals = [int(v) for v in vals.split()]
print(int_vals) # [-268, 14, 7, 19]
print(date) # Fri Aug 3 12:32:08 2018
Using regex
import re
match = re.search(r'([-\d]+) ([-\d]+) ([-\d]+) ([-\d]+)[ -]*(.*)', string)
date = match.group(5)
int_vals = [int(v) for v in match.groups()[:4]] # same results
Use str.split
Ex:
String = '-268 14 7 19 - Fri Aug 3 12:32:08 2018\n'
first, second = String.split(" - ")
first = tuple(int(i) for i in first.split())
print(first)
print(second)
Output:
(-268, 14, 7, 19)
Fri Aug 3 12:32:08 2018
Use split and map for it:
left, date = String.split(' - ')
numbers = list(map(int, left.split()))
print(numbers, date)

Rendering Text Calendar

I have a function which is supposed to build a header for a calendar like so:
' Sun Mon Tue Wed Thu Fri Sat '
It takes a isoweekday (one of '#Monday' 1, 2, 3, 4, 5, 6, 7 '#Sunday').
Here is the code:
#staticmethod
def _isoweekday_to_str(isoweekday):
isoweekday = isoweekday - 1
isoweekday = str(isoweekday)
x = datetime.strptime(isoweekday, '%w')
return x.strftime('%a')
TEXT_CAL_MONTH_WEEK_HEADER = ""
iter_isoweekday = week_start
for _ in range(0,7):
TEXT_CAL_MONTH_WEEK_HEADER += self._isoweekday_to_str(iter_isoweekday).rjust(TEXT_CAL_CELL_WIDTH, " ")
if iter_isoweekday != 7:
iter_isoweekday += 1
else:
iter_isoweekday = 1
The output I'm getting, when passing in 4 as the week start, is:
' Mon Mon Mon Mon Mon Mon Mon '
it should be:
' Thu Fri Sat Sun Mon Tue Wed '
I'm really, really not sure what's going on. I think it's either something to do with the way variables are assigned, string mutation, or the datetime library.
UPDATE: it appears that datetime.strptime is the problem. No matter what I pass in, I get datetime(1900, 1, 1, 0, 0) back... which, you guessed it, was a Monday.
Help?
You can get the localised days of the week from the calendar module:
>>> import calendar
>>> list(calendar.day_name)
['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
Or the abbreviated names, using calendar.day_abbr:
>>> ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
See the documentation if you need other locales.
Obviously, the module can produce whole calendars:
>>> print calendar.TextCalendar().formatmonth(2016, 1)
January 2016
Mo Tu We Th Fr Sa Su
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
I'm not sure why you want to do it this way, but you need an actual date to pass to strptime rather than an isoweekday. For example,
from datetime import datetime
TEXT_CAL_CELL_WIDTH = 5
def _isoweekday_to_str(isoweekday):
isoweekday = '1900-01-{:02d}'.format(isoweekday)
x = datetime.strptime(isoweekday, '%Y-%m-%d')
return x.strftime('%a')
TEXT_CAL_MONTH_WEEK_HEADER = ""
week_start = 4
iter_isoweekday = week_start
for _ in range(0,7):
TEXT_CAL_MONTH_WEEK_HEADER += _isoweekday_to_str(iter_isoweekday).rjust(TEXT_CAL_CELL_WIDTH, " ")
if iter_isoweekday != 7:
iter_isoweekday += 1
else:
iter_isoweekday = 1
print(TEXT_CAL_MONTH_WEEK_HEADER )
Output:
Thu Fri Sat Sun Mon Tue Wed
(This works because 01/01/1900 was a Monday).
But why not do something similar with a dictionary of day names:
day_names = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
def weekday_header(week_start):
header = ''.join(['{:4s}'.format(day_names[(day_number+week_start) % 7])
for day_number in range(7)])
return header
print(weekday_header(4))

Categories