Print month using the month and day - python

I need to print month using the month and day. But I cannot seem to move the numbers after '1' to the next line using Python.
# This program shows example of "November" as month and "Sunday" as day.
month = input("Enter the month('January', ...,'December'): ")
day = input("Enter the start day ('Monday', ..., 'Sunday'): ")
n = 1
if month == "January" or month == "March" or month == "May" or month == "July" or month == "August" or month == "October" or month == "December":
x = 31
elif month == "February":
x = 28
else:
x = 30
print(month)
print("Mo Tu We Th Fr Sa Su")
if (day == "Sunday"):
print(" ", end='')
for i in range (1, 7):
for j in range (1, 8):
while n != x+1:
print('%2s' % n, end=' ')
n = n + 1
break
print()
Output looks like this:
November
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

Some changes.
Instead of having a nested loop, just have a single loop that prints all the dates. Then, inside that loop, make the decision about whether to end the line (if the date you just printed corresponded to a Sunday).
Also, the # of days in month look-up is a bit cleaner, and you now handle more "days" than just Sunday:
day = "Monday"
month = "March"
# Get the number of days in the months
if month in ["January", "March", "May", "July", "August", "October", "December"]:
x = 31
elif month in ["February"]:
x = 28
else:
x = 30
# Get the number of "blank spaces" we need to skip for the first week, and when to break
DAY_OFF = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
off = DAY_OFF.index(day)
print(month)
print("Mo Tu We Th Fr Sa Su")
# Print empty "cells" when the first day starts after Monday
for i in range(off):
print(" ", end=' ')
# Print days of the month
for i in range(x):
print("%2d" % (i+1), end=' ')
# If we just printed the last day of the week, print a newline
if (i + off) % 7 == 6: print()
March/Monday
March
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
March/Sunday
March
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
February/Sunday
February
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

First problem I see in your code, is: why are you using an while and a break just after start it?
It seems that you only need an if statement, not a while.
Second, you're using the same logic for any line of your calendar, that means: They start on Monday and end on Sunday.
You should change the start point of your inner for loop for your first line, depending on the day that it starts.
A simple dictionary can hold the number associated with each day of the week and for the first week you use it as the start point of the for instead of 1.
And your code will work only for Monday and Sunday as the first day of the month.
To make it works for any first day you should change the way you print spaces, changing it depending on the first day.
The code with the changes:
month = 'November'
day = 'Sunday'
x = 30
n = 1
days = { 'Mo': 1, 'Tu': 2, 'We': 3, 'Th': 4, 'Fr': 5, 'Sa': 6, 'Su': 7 }
print(" "*(days[day[:2]]-1), end='') # print 3 spaces for each day that isn't the first day of the month
start = days[day[:2]] # Set the start of the inner loop to the first day of the month
for i in range (1, 7):
for j in range (start, 8):
start = 1
if n < x+1:
print('%2s' % n, end=' ')
n = n + 1
print()

Related

Formatting Number Outputs using Fixed Point decimal precision while still removing trailing Zeros? (Python 3.7.7)

PYTHON 3.7.7
For a school assignment, I have to submit code using an evil program called Mimir. Basically if my output is not pixel-perfect, I get a fail on the test case (15min writing a code, 50min making the output "look right").
Question:
I have no clue how to get my number outputs to look like the assignment's. My shown attempt here uses the 'g' format, as it is the only format modifier that removes trailing zeros and removes the decimal point when necessary. I need to be able to do this while maintaining a '.6' precision. Also, how do I make it that the output is never displayed in scientific notation.
Thank you for the help!
MY CODE:
#Asking user to define parameters for the calculation
Organs = float(input('Starting number of organisms: \n'))
DailyInc = float(input('Average daily increase: \n'))
DaysX = int(input('Number of days to multiply: \n'))
#Doing % to decimal calc. only one to make program work faster
Inc = (1 + (DailyInc / 100))
#Print table heading and first day
print('Day Approximate Population')
print('1', ' ', format(Organs, 'g'))
#Loop to calculate running daily total and print using format hell
for Day in range (2, DaysX + 1):
Organs = Organs * Inc
if Day >= 100:
print(Day," ", format(Organs, 'g'))
elif Day >= 10:
print(Day," ", format(Organs, 'g'))
else:
print(Day," ", format(Organs, 'g'))
MY OUTPUT (input - 2, 30, 60):
Starting number of organisms:
Average daily increase:
Number of days to multiply:
Day Approximate Population
1 2
2 2.6
3 3.38
4 4.394
5 5.7122
6 7.42586
7 9.65362
8 12.5497
9 16.3146
10 21.209
11 27.5717
12 35.8432
13 46.5962
14 60.575
15 78.7475
16 102.372
17 133.083
18 173.008
19 224.911
20 292.384
21 380.099
22 494.129
EXPECTED OUTPUT (input - 2, 30, 60):
Starting number of organisms:
Average daily increase:
Number of days to multiply:
Day Approximate Population
1 2
2 2.6
3 3.38
4 4.394
5 5.7122
6 7.42586
7 9.653618
8 12.549703
9 16.314614
10 21.208999
11 27.571698
12 35.843208
13 46.59617
14 60.575021
15 78.747528
16 102.371786
17 133.083322
18 173.008318
19 224.910814
20 292.384058
21 380.099275
22 494.129058
try something like this:
val1 = 1.2635485547884475
val2 = 1.2
print(val1)
print(f'{val1:.2f}')
print(f'{val1:.6f}')
print(f'{val2:.6f}')
output:
1.2635485547884475
1.26
1.263549
1.200000
First example is displayed on a single line to demonstrate formating
val1 = 1.2635485547884475
val2 = 1.2
print(f'{val1:<17.15f}', end = " ")
print(f'{val1:<7.5f}', end = " ")
print(f'{val2:<4.2g}')
print(f'{val1:<17.15f}')
print(f'{val1:<7.5f}')
print(f'{val2:<4.2g}')

problem with if else loop for a month and days problem

why do I get the wrong output for the code below, I've put the output below
(some might suggest using date-time module, I'm going with this method due to some complications with the main program)
months = [1,2,3,4,5,6,7,8,9,10,11,12]
for month in months:
if month == {1,3,5,7,9,11}:
days= 31
print(days)
elif month == {4,6,8,10,12}:
days = 30
print(days)
else :
days = 28
print(days)
I get this output
28
28
28
28
28
28
28
28
28
28
28
28
Question approach
You are checking if an integer is equal to a set. You want to check if the integer is in the set. By the way, the sets you use are wrong (fixed here) and february may have 29 days (not fixed in this solution).
for month in range(1, 13):
if month in {1, 3, 5, 7, 8, 10, 12}:
days = 31
elif month in {4, 6, 9, 11}:
days = 30
else :
days = 28
print(f"{month:2}: {days}")
1: 31
2: 28
3: 31
4: 30
5: 31
6: 30
7: 31
8: 31
9: 30
10: 31
11: 30
12: 31
Calendar approach
Another solution is to use the calendar module which fixed the 29 days on february issue.
import calendar
for month in range(1, 13):
days = calendar.monthrange(2020, month)[1]
print(f"{month:2}: {days}")
1: 31
2: 29
3: 31
4: 30
5: 31
6: 30
7: 31
8: 31
9: 30
10: 31
11: 30
12: 31

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

Is there a way to break from a range() function at a specific value?

I am new to programming in python and am trying to design a calendar that starts the month depending on the selected start day.
However, I don't know how to stop the print once the number of days has been exceeded(e.g breaks at days=31 when month=="January")
The printed values must be right-aligned additionally.
Here is how I first approached it:
month=input("Enter the month: ")
if month=="January" or month=="March" or month=="May" or month=="July" or month=="August" or month=="October" or month=="December":
days=31
else:
days=30
if month=="February":
days=28
Start_day=input("Enter the start day: ")
print(month)
print("Mo","Tu","We","Th","Fr","Sa","Su")
if Start_day == "Monday":
i=1
if Start_day == "Tuesday":
i=0
if Start_day == "Wednesday":
i=-1
if Start_day == "Thursday":
i=-2
if Start_day == "Friday" :
i=-3
if Start_day == "Saturday":
i=-4
if Start_day == "Sunday":
i=-5
j=1
for j in range(i,days,7):
print(str(j).rjust(2," "),str(j+1).rjust(2," "),str(j+2).rjust(2," "),str(j+3).rjust(2," "),str(j+4).rjust(2," "),str(j+5).rjust(2," "),str(j+6).rjust(2," "))
You could encode it instead as
j=1
for j in range(i,days,7):
for i in range(0,7):
if j+i>days: break
print(str(j+i).rjust(2," "),end=' ')
print('')
This would be called "breaking out of a loop" rather than "breaking from a range function." There is no way to "break from a range function."
Can I suggest overhauling this a bit to be more efficient? You can use dicts and define a custom function to handle the date formatting to prevent some repetition.
To answer your question, you can evaluate the date number during the final loop:
for j in range(i,days,7):
# add to j value via range() and adjust()
# (defined above) to prevent repetition
for k in range(7):
if j + k > 0 and j + k <= days:
print(adjust(j + k), end = ' ') # don't print new line
else:
# print spaces if the number is <1 or >days
print(' ', end = '')
# print new line for a new week
print('\n', end = '')
Full example:
# function to format dates later
def adjust(val):
return str(val).rjust(2," ")
# get inputs
month=input("Enter the month: ")
start_day=input("Enter the start day: ")
# map months to days in a dict
month_to_days={"january":31,
"march":31,
"may":31,
"july":31,
"august":31,
"october":31,
"december":31,
"february":28,
"april":30,
"june":30,
"september":30,
"october":30
}
# map weekdays to int
days_to_int={"monday":1,
"tuesday":0,
"wednesday":-1,
"thursday":-2,
"friday":-3,
"saturday":-4,
"sunday":-5
}
# get the day amount based on the entry, ignoring case
days=month_to_days[month.lower()]
# get the int based on the entry, ignoring case
i=days_to_int[start_day.lower()]
# print month and day headers
print(month)
print("Mo","Tu","We","Th","Fr","Sa","Su")
for j in range(i,days,7):
# add to j value via range() and adjust()
# (defined above) to prevent repetition
for k in range(7):
if j + k > 0 and j + k <= days:
print(adjust(j + k), end = ' ') # don't print new line
else:
# print spaces if the number is <1 or >days
print(' ', end = '')
# print new line for a new week
print('\n', end = '')
Output:
Enter the month: january
Enter the start day: monday
january
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
>>>
Enter the month: june
Enter the start day: wednesday
june
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
Before you print after your for loop just have an if statement to check for your condition and before you print add a break statement.
Something like:
if statement:
break

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