Output formate for calendar in Python 3.6 - python-3.x

I would like to format the output in terms of calendar format. I have tried with print statement, but could not achieve as I expected because rows and column is not aligned properly.Could anyone help me to format and align the output? Here I have shared my entire code which is written in Python 3.6. the same question I have asked before but could not get any reply. but this code is little better than my previous code.
import calendar
import datetime
tamil_day = ('Monday','Tuesday','Wednesday','Thusday','Friday','Saturday','Sunday')
tamil_month = ('Chithirai','Vaikasi','Aani','Aadi','Aavani','Puratasi','Ipasi','Karthikai','Maargali','Thai','Masi','Panguni')
'''SAKA year Each month starting day in AD year 1st position for common year and 0th position for leap year'''
saka_month_starting_day_in_ad = (21,22,21,22,22,23,23,23,23,22,22,21,20)
'''equal month in AD year for SAKA month starting'''
ad_month = (3,3,4,5,6,7,8,9,10,11,12,1,2)
''' number of days in each month in SAKA year. add one ine more day each month for calculation'''
no_days_in_saka_month = (31,30,31,31,31,31,31,30,30,30,30,30,30)
def saka_month(saka_year,month):
ad_year = saka_year+78
saka_month = []
temp = 0
if month == 1 and calendar.isleap(ad_year):
first_day = datetime.date(ad_year,ad_month[month],saka_month_starting_day_in_ad[month-1]).weekday()
else:
first_day = datetime.date(ad_year,ad_month[month],saka_month_starting_day_in_ad[month]).weekday()
while first_day != temp:
saka_month.append(str(' '))
temp+=1
for day in range(1,(no_days_in_saka_month[month]+1)):
saka_month.append(str(day))
if day == no_days_in_saka_month[month] and calendar.isleap(ad_year):
saka_month.append(str(day+1))
for i in range(0,42,7):
print(*saka_month[i:i+7],sep=' ',end='\n')
print('\n')
def saka_year_print(saka_year):
for month in range(0,12):
print('{:*^80}'.format(tamil_month[month]))
print('\n')
print(*tamil_day,sep=' ')
print('\n','\n','\n')
saka_month(saka_year,month)

i have found the solution to my problem. just add str.center() for every list element. in my code at line no.47,50 and 52 you can add the center() function so that we can get aligned matrix kind of calendar in month view.
thank you

Related

one function used to change variable in another function

# making a basic calendar
#list of months and their days
month_day = [[1,'January',31],[2,'February',28],
[3,'March',31],[4,'April',30],
[5,'May',31],[6,'June',30],
[7,'July',31],[8,'August',31],
[9,'September',30],[10,'October',31],
[11,'November',30],[12,'December',31]]
#checksum for new year
def isleapyear(year):
if year%4 == 0:
if year%100 == 0:
if year%400 == 0:
month_day[1][2] = 29
else:
month_day[1][2] = 28
else :
month_day[1][2] = 29
else:
month_day[1][2] = 28
#editable date (supposed to be
def Date():
year = 1
day = 31
month = 1
isleapyear(year)
date = [day, month_day[month-1][1], year]
return date
#function to increase day counter by 1
def new_day():
#checksum for month or year rollover
if Date.day == month_day[Date.month-1][2]:
Date.day = 1
if Date.month == 12:
Date.month = 1
Date.year = Date.year + 1
else:
Date.month = month + 1
else:
Date.day = Date.day + 1
new_day()
print (Date())
I am trying to teach myself python, so I have made a project a few smaller projects working together and one of them is a Date tracker. The Date function works. however when i try to call the new day function to bump the day by 1 and change month and year if needed, i get an error "AttributeError: 'function' object has no attribute 'day'". I understand that inside a function is a separate local variable not a global and that your not supposed to make global variables constantly changing. So I'm trying to get one function to call and use anothers variable I plan on making it into a button that changes the day by 1 or 7, I'm just having trouble visualizing how to get the function working. Any direction or help with getting this to work would be greatly appreciated
Thank you all in advance!
Firstly, you can't get variables from function.
One way you can deal with it is in function Date add line global year, day, month, this will make variables year, day, month global so you can use it in all function and outside of functions. And in new_day remove Date..
This should get rid of your problem.
Date.day would only work if Date was class not function.
For example:
class Date:
def __init__(self):
self.year = 1
self.day = 31
self.month = 1
Date().year # Should return 1
Date().day # Should return 31
Date().month # Should return 1

How to get 1st calendar day of the current and next month based on a current date variable

I have a date variable calls today_date as below. I need to get the 1st calendar day of the current and next month.
In my case, today_date is 4/17/2021, I need to create two more variables calls first_day_current which should be 4/1/2021, and first_day_next which should be 5/1/2021.
Any suggestions are greatly appreciated
import datetime as dt
today_date
'2021-04-17'
Getting just the first date of a month is quite simple - since it equals 1 all the time. You can even do this without needing the datetime module to simplify calculations for you, if today_date is always a string "Year-Month-Day" (or any consistent format - parse it accordingly)
today_date = '2021-04-17'
y, m, d = today_date.split('-')
first_day_current = f"{y}-{m}-01"
y, m = int(y), int(m)
first_day_next = f"{y+(m==12)}-{m%12+1}-01"
If you want to use datetime.date(), then you'll anyway have to convert the string to (year, month, date) ints to give as arguments (or do today_date = datetime.date.today().
Then .replace(day=1) to get first_day_current.
datetime.timedelta can't add months (only upto weeks), so you'll need to use other libraries for this. But it's more imports and calculations to do the same thing in effect.
I found out pd.offsets could accomplish this task as below -
import datetime as dt
import pandas as pd
today_date #'2021-04-17' this is a variable that is being created in the program
first_day_current = today_date.replace(day=1) # this will be 2021-04-01
next_month = first_day_current + pd.offsets.MonthBegin(n=1)
first_day_next = next_month.strftime('%Y-%m-%d') # this will be 2021-05-01

extract last day and first day from month in python

i am new in python ,i have a string of this format
Ex. 'Mar-00'
how could i calculate first day and last day from this month.
OUTPUT :
first day : 01-Mar-00
last day : 31-Mar-00
ex : 'Feb-17'
first day : 01-Feb-17
last day : 28-Feb-17
you can use calendar.monthrange(year, month)[1] to get the number of days in a given month+year.
the first is alway 01, and last is the value of calendar.monthrange(year, month)[1]
try this, let me know if it works:
import calendar
month_abbr_to_num = {v: k for k,v in enumerate(calendar.month_abbr)}
month_abbr, year_2_digit = input("please enter month, e.g. Mar-00: ").split('-')
month = month_abbr_to_num[month_abbr]
year = int('20'+year_2_digit)
days_in_month = calendar.monthrange(year,month)[1]
print("first day : {:02d}-{}-{}".format(1, month_abbr, year_2_digit))
print("last day : {:02d}-{}-{}".format(days_in_month, month_abbr, year_2_digit))
EDIT:
following your comment on original question, here it is in the form of a function that returns both as datetime objects:
import calendar
import datetime
month_abbr_to_num = {v: k for k,v in enumerate(calendar.month_abbr)}
def get_first_and_last_day(user_input):
month_abbr, year_2_digit = user_input.split('-')
month = month_abbr_to_num[month_abbr]
year = int('20' + year_2_digit)
days_in_month = calendar.monthrange(year, month)[1]
first_day = datetime.datetime(year, month, 1)
last_day = datetime.datetime(year, month, days_in_month)
return first_day, last_day
first, last = get_first_and_last_day(input("please enter month, e.g. Mar-00: "))
print("first day : ",first)
print("last day : ",last)

How to calculate total precipitation per day using hourly data for whole year?

I have hourly data from ERA5 for each day in a specific year. I want to convert that data from hourly to daily. I know the long and hard way to do it, but I need something which does that easily.
Copernicus has a code for this here https://confluence.ecmwf.int/display/CKB/ERA5%3A+How+to+calculate+daily+total+precipitation, which works fine if the data set is only converted for one day, but when converting for the whole year, i am having problems with that.
Link to download ERA5 dataset which is available at https://cds.climate.copernicus.eu/cdsapp#!/home
Follow the steps to use copernicus server here
https://confluence.ecmwf.int/display/CKB/How+to+download+ERA5
This script downloads the houly data for only 2 days (1st and 2nd of January 2017):
#!/usr/bin/env python
"""
Save as get-tp.py, then run "python get-tp.py".
Input file : None
Output file: tp_20170101-20170102.nc
"""
import cdsapi
c = cdsapi.Client()
r = c.retrieve(
'reanalysis-era5-single-levels', {
'variable' : 'total_precipitation',
'product_type': 'reanalysis',
'year' : '2017',
'month' : '01',
'day' : ['01', '02'],
'time' : [
'00:00','01:00','02:00',
'03:00','04:00','05:00',
'06:00','07:00','08:00',
'09:00','10:00','11:00',
'12:00','13:00','14:00',
'15:00','16:00','17:00',
'18:00','19:00','20:00',
'21:00','22:00','23:00'
],
'format' : 'netcdf'
})
r.download('tp_20170101-20170102.nc')
## Add multiple days and multiple months to donload more data
Below script will create a netCDF file for only one day
#!/usr/bin/env python
"""
Save as file calculate-daily-tp.py and run "python calculate-daily-tp.py".
Input file : tp_20170101-20170102.nc
Output file: daily-tp_20170101.nc
"""
import time, sys
from datetime import datetime, timedelta
from netCDF4 import Dataset, date2num, num2date
import numpy as np
day = 20170101
d = datetime.strptime(str(day), '%Y%m%d')
f_in = 'tp_%d-%s.nc' % (day, (d + timedelta(days = 1)).strftime('%Y%m%d'))
f_out = 'daily-tp_%d.nc' % day
time_needed = []
for i in range(1, 25):
time_needed.append(d + timedelta(hours = i))
with Dataset(f_in) as ds_src:
var_time = ds_src.variables['time']
time_avail = num2date(var_time[:], var_time.units,
calendar = var_time.calendar)
indices = []
for tm in time_needed:
a = np.where(time_avail == tm)[0]
if len(a) == 0:
sys.stderr.write('Error: precipitation data is missing/incomplete - %s!\n'
% tm.strftime('%Y%m%d %H:%M:%S'))
sys.exit(200)
else:
print('Found %s' % tm.strftime('%Y%m%d %H:%M:%S'))
indices.append(a[0])
var_tp = ds_src.variables['tp']
tp_values_set = False
for idx in indices:
if not tp_values_set:
data = var_tp[idx, :, :]
tp_values_set = True
else:
data += var_tp[idx, :, :]
with Dataset(f_out, mode = 'w', format = 'NETCDF3_64BIT_OFFSET') as ds_dest:
# Dimensions
for name in ['latitude', 'longitude']:
dim_src = ds_src.dimensions[name]
ds_dest.createDimension(name, dim_src.size)
var_src = ds_src.variables[name]
var_dest = ds_dest.createVariable(name, var_src.datatype, (name,))
var_dest[:] = var_src[:]
var_dest.setncattr('units', var_src.units)
var_dest.setncattr('long_name', var_src.long_name)
ds_dest.createDimension('time', None)
var = ds_dest.createVariable('time', np.int32, ('time',))
time_units = 'hours since 1900-01-01 00:00:00'
time_cal = 'gregorian'
var[:] = date2num([d], units = time_units, calendar = time_cal)
var.setncattr('units', time_units)
var.setncattr('long_name', 'time')
var.setncattr('calendar', time_cal)
# Variables
var = ds_dest.createVariable(var_tp.name, np.double, var_tp.dimensions)
var[0, :, :] = data
var.setncattr('units', var_tp.units)
var.setncattr('long_name', var_tp.long_name)
# Attributes
ds_dest.setncattr('Conventions', 'CF-1.6')
ds_dest.setncattr('history', '%s %s'
% (datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
' '.join(time.tzname)))
print('Done! Daily total precipitation saved in %s' % f_out)
What I want is a code which will follows the same step as above data but assuming that I have an input file with one year houly data and convert that to one year daily data.
The result should be daily values for the calculate variable (such as precipitation, etc) for the whole year.
Example: Let's say I have a precipitation data for the whole year as 1mm/hr every day, I would have 2928 values for the whole year.
What I want is 24mm/day for the whole year with only 365 values for a non-leap year.
Example input dataset: Subset of the data can be downloaded from here (for 1st and 2nd January 2017) https://www.dropbox.com/sh/0vdfn20p355st3i/AABKYO4do_raGHC34VnsXGPqa?dl=0. Just use the 2nd script after this to check the code. {the code for the whole year is >10 GB thus can't be uploaded
Thanks in advance
xarray resample is just the tool for you. It converts netCDF data from one temporal resolution (e.g. hourly) to another (e.g. daily) in one line. Using your sample data file, we can create daily-means using the following code:
import xarray as xr
ds = xr.open_dataset('./tp_20170101-20170102.nc')
tp = ds['tp'] # dimensions [time: 48, latitude: 721, longitude: 1440]
tp_daily = tp.resample(time='D').mean(dim='time') # dimensions (time: 2, latitude: 721, longitude: 1440)
You'll see that the resample command takes in a temporal code, in this case 'D' which means daily and then we specify that we want to compute the mean for each day using the hourly data of that day with .mean(dim='time').
If instead, for example, you wanted to compute the daily max rather than the daily mean, you'd replace .mean(dim='time') with .max(dim='time'). You can also go from hourly to monthly (MS or month-start), annual (AS or annual-start), and many more. The temporal frequency codes can be found in the Pandas docs.
An alternative quick method from the command line using CDO would be:
cdo daysum -shifttime,-1hour era5_hourly.nc era5_daily.nc
Note, as per this answer/discussion here: Calculating ERA5 Daily Total Precipitation using CDO
the ERA5 hourly data has the timestep at the end of the hourly window, so you need to shift the timestamp before making the sum, I'm not sure the xarray solution handles that. Also to have mm/day, I think one needs to sum, not take the mean.

How i find out which person stayed maximum nights? Name and total how many days?

How i find out which person stayed maximum nights? Name and total how many days? (date format MM/DD)
for example
text file contain's
Robin 01/11 01/15
Mike 02/10 02/12
John 01/15 02/15
output expected
('john', 30 )
my code
def longest_stay(fpath):
with open(fpath,'r')as f_handle:
stay=[]
for line in f_handle:
name, a_date, d_date = line.strip().split()
diff = datetime.strptime(d_date, "%m/%d") -datetime.strptime(a_date, "%m/%d")
stay.append(abs(diff.days+1))
return name,max(stay)
It always return first name.
This can also be implemented using pandas. I think it will much simpler using pandas.
One issue I find is that how you want to handle when you have many stayed for max nights. I have addressed that in the following code.
import pandas as pd
from datetime import datetime as dt
def longest_stay(fpath):
# Reads the text file as Dataframe
data = pd.read_csv(fpath + 'test.txt', sep=" ", header = None)
# adding column names to the Data frame
data.columns = ['Name', 'a_date', 'd_date']
# Calculating the nights for each customer
data['nights'] = datetime.strptime(d_date, "%m/%d") - datetime.strptime(a_date, "%m/%d")
# Slicing the data frame by applying the condition and getting the Name of the customer and nights as a tuple (as expected)
longest_stay = tuple( data.ix[data.nights == data.nights.max(), {'Name', 'nights'}])
# In case if many stayed for the longest night. Returns a list of tuples.
longest_stay = [tuple(x) for x in longest_stay]
return longest_stay
Your code fails but not storing the first name, it is because name is going to be set to the last name in the file because you only store the days as you go, hence you always see the last name.
You also add + 1 which does not seem correct as you should not be adding or including the last day as the person does not stay that night. Your code would actually output ('John', 32) the correct name by chance because it is the last in your sample file and the day off by 1.
Just keep track of the best which includes the name and day count as you go using the days stayed as the measure and return that at the end:
from datetime import datetime
from csv import reader
def longest_stay(fpath):
with open(fpath,'r')as f_handle:
mx,best = None, None
for name, a_date, d_date in reader(f_handle,delimiter=" "):
days = (datetime.strptime(d_date, "%m/%d") - datetime.strptime(a_date, "%m/%d")).days
# first iteration or we found
if best is None or mx < days:
best = name, days
return best
Outout:
In [13]: cat test.txt
Robin 01/11 01/15
Mike 02/10 02/12
John 01/15 02/15
In [14]: longest_stay("test.txt")
# 31 days not including the last day as a stay
Out[14]: ('John', 31)
You only need to use abs if the format is not always in the format start-end but be aware would could get the wrong output using the abs value if your dates had years.

Resources