Need to output the remaining holidays in the txt file using python - python

happy holidays!
I am working on the project that needs to send reminders about public holidays 3 weeks in advance. I have completed this part and now need to add a function that will also send the remaining holidays for the year in addition to the upcoming holiday. Any tips or suggestions on how I can approach this will be greatly appreciated as I am new to coding!
Here is the code I have for now:
import datetime
from datetime import timedelta
import calendar
import time
import smtplib as smtp
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.message import EmailMessage
holidayFile = 'calendar.txt'
def run(input):
checkTodaysHolidays()
def checkTodaysHolidays():
file = open(holidayFile, 'r')
date = (datetime.date.today() + datetime.timedelta(days=21)).strftime('%Y/%m/%d')
publicHolidayName = ''
for line in file:
if date in line:
publicHolidayName = " ".join(line.split()[1:])
Thank you.

I think the easiest way to do this would be to use the datetime and timedelta modules you've already imported.
I would convert the data in your text file into an array, and then build a function that compares today's date to the holidays in this list.
holidayFile = open('calendar.txt', 'r')
holidayLines = holidayFile.readlines()
holidayFile.close()
holidayNames = []
holidayDates = []
for x in range(0, len(holidayLines) ):
# ... Get the date, first
this = holidayLines[x].split(" ") # since we know they're formatted "YYYY/MM/DD Name of Holiday"
rawdate = this[0]
datechunks = rawdate.split("/") # separate out the YYYY, MM, and DD for use
newdate = (datechunks[0] ,datechunks[1] , datechunks[2])
holidayDates.append(newdate)
# ... then get the Name
del this[0] # remove the dates from our split array
name = "".join(this)
holidayNames.append(name)
So in the block before our function, I:
1: Open the file and store each line, then close it.
2: Iterate through each line and separate out the date, and store the touples in an array.
3: Save the name to a separate array.
Then we do the comparison.
def CheckAllHolidays():
returnNames = [] # a storage array for the names of each holiday
returnDays = [] # a storage array for all the holidays that are expected in our response
today = datetime.datetime.now()
threeweeks = timedelta(weeks=3)
for x in range(0, len(holidayDates) ):
doi = holidayDates[x] # a touple containing the date of interest
year = doi[0]
month = doi[1]
day = doi[2]
holiday = datetime.datetime(year, month, day)
if holiday > today:
# convert the holiday date to a date three weeks earlier using timedelta
returnDays.append( holiday - threeweeks )
returnNames.append( holidayNames[x] )
else:
pass # do nothing if date has passed
return(returnDays, returnNames)
What I did here is I:
1: Create an array inside the function to store our holiday names.
2: Convert the date from the previous array into a datetime.datetime() object.
3: Compare two objects of like kind in an if block, and
4: Return a list of dates three-weeks before each holiday, with names for the holidays that a reminder should be set for.
Then you're all set. You could call
ReminderDates = CheckAllHolidays()[0]
ReminderNames = CheckAllHolidays()[1]
and then use those two lists to create your reminders! ReminderDates would be an array filled with datetime.datetime() objects, and ReminderNames would be an array filled with string values.
I'm sorry my response was kinda long, but I really hope I was able to help you with your issue! Happy Holidays <3

Related

Sorting datetime; pandas

I have a big excel file with a datetime format column which are in strings. The column looks like this:
ingezameldop
2022-10-10 15:51:18
2022-10-10 15:56:19
I have found two ways of trying to do this, however they do not work.
First (nice way):
import pandas as pd
from datetime import datetime
from datetime import date
dagStart = datetime.strptime(str(date.today())+' 06:00:00', '%Y-%m-%d %H:%M:%S')
dagEind = datetime.strptime(str(date.today())+' 23:00:00', '%Y-%m-%d %H:%M:%S')
data = pd.read_excel('inzamelbestand.xlsx', index_col=9)
data = data.loc[pd.to_datetime(data['ingezameldop']).dt.time.between(dagStart.time(), dagEind.time())]
data.to_excel("oefenexcel.xlsx")
However, this returns me with an excel file identical to the original one. I cant seem to fix this.
Second way (sketchy):
import pandas as pd
from datetime import datetime
from datetime import date
df = pd.read_excel('inzamelbestand.xlsx', index_col=9)
# uitfilteren dag van vandaag
dag = str(date.today())
dag1 = dag[8]+dag[9]
vgl = df['ingezameldop']
vgl2 = vgl.str[8]+vgl.str[9]
df = df.loc[vgl2 == dag1]
# uitfilteren vanaf 6 uur 's ochtends
# str11 str12 = uur
df.to_excel("oefenexcel.xlsx")
This one works for filtering out the exact day. But when I want to filter out the hours it does not. Because I use the same way (getting the 11nd and 12th character from the string) but I cant use logic operators (>=) on strings, so I cant filter out for times >6
You can modify this line of code
data = data.loc[pd.to_datetime(data['ingezameldop']).dt.time.between(dagStart.time(), dagEind.time())]
as
(dagStart.hour, dagStart.minute) <= (data['ingezameldop'].hour, data['ingezameldop'].minute) < (dagEind.hour, dagEind.minute)
to get boolean values that are only true for records within the date range.
dagStart, dagEind and data['ingezameldop'] must be in datetime format.
In order to apply it on individual element of the column, wrap it in a function and use apply as follows
def filter(ingezameldop, dagStart, dagEind):
return (dagStart.hour, dagStart.minute) <= (data['ingezameldop'].hour, data['ingezameldop'].minute) < (dagEind.hour, dagEind.minute)
then apply the filter on the column in this way
data['filter'] = data['ingezameldop'].apply(filter, dagStart=dagStart, dagEind=dagEind)
That will apply the function on individual series element which must be in datetime format

Select date range with Tkinter

I'm trying to make a tkinter app where the user can select a date range.
The Tkcalendar library only allows to select 1 day, is there a way to select multiple continuous days?
Thank you very much
You can create two calendars and then choose two dates and then find the range between those two dates. The core function would be:
def date_range(start,stop): # Start and stop dates for range
dates = [] # Empty list to return at the end
diff = (stop-start).days # Get the number of days between
for i in range(diff+1): # Loop through the number of days(+1 to include the intervals too)
day = first + timedelta(days=i) # Days in between
dates.append(day) # Add to the list
if dates: # If dates is not an empty list
return dates # Return it
else:
print('Make sure the end date is later than start date') # Print a warning
Now to put things in tkinter perspective, button callbacks cannot return anything, so this should be something like:
from tkinter import *
import tkcalendar
from datetime import timedelta
root = Tk()
def date_range(start,stop):
global dates # If you want to use this outside of functions
dates = []
diff = (stop-start).days
for i in range(diff+1):
day = start + timedelta(days=i)
dates.append(day)
if dates:
print(dates) # Print it, or even make it global to access it outside this
else:
print('Make sure the end date is later than start date')
date1 = tkcalendar.DateEntry(root)
date1.pack(padx=10,pady=10)
date2 = tkcalendar.DateEntry(root)
date2.pack(padx=10,pady=10)
Button(root,text='Find range',command=lambda: date_range(date1.get_date(),date2.get_date())).pack()
root.mainloop()
Keep in mind, the list is full of datetime objects, to make a list full strings of date alone, say:
dates = [x.strftime('%Y-%m-%d') for x in dates] # In the format yyyy-mm-dd

Get filename and date time from string

I have file names in the following format: name_2016_04_16.txt
I'm working with python3 and I would like to extract two things from this file. The prefix, or the name value as a string and the date as a DateTime value for the date represented in the string. For the example above, I would like to extract:
filename: name as a String
date: 04/16/2016 as a DateTime
I will be saving these values to a database, so I would like the DateTime variable to be sql friendly.
Is there a library that can help me do this? Or is there a simple way of going about this?
I tried the following as suggested:
filename = os.path.splitext(filename)[0]
print(filename)
filename.split("_")[1::]
print(filename)
'/'.join(filename.split("_")[1::])
print(filename)
But it outputs:
name_2016_04_16
name_2016_04_16
name_2016_04_16
And does not really extract the name and date.
Thank you!
I would first strip the file extension, then I would split by underscore, removing the 'name' field. Finally, I would join by slash (maybe this value could be logged) and parse the date with the datetime library
import os
from datetime import datetime
file_name = os.path.splitext("name_2016_04_16.txt")[0]
date_string = '/'.join(file_name.split("_")[1::])
parsed_date = datetime.strptime(date_string, "%Y/%m/%d")
To make the date string sql friendly, I found this so post: Inserting a Python datetime.datetime object into MySQL, which suggests that the following should work
sql_friendly_string = parsed_date.strftime('%Y-%m-%d %H:%M:%S')
How about simply doing this?
filename = 'name_2016_04_16.txt'
date = filename[-14:-4] # counting from the end will ensure that you extract the date no matter what the "name" is and how long it is
prefix = filename [:-14]
from datetime import datetime
date = datetime.strptime(date, '%Y_%m_%d') # this turns the string into a datetime object
(However, this works on Python 2.7, if it works for Python 3 you need to find for yourself.)
You can split the filename on "." Then split again on "_". This should give you a list of strings. The first being the name, second through fourth being the year, month and day respectively. Then convert the date to SQL friendly form.
Something like this:
rawname ="name_2016_04_16.txt"
filename = rawname.split(".")[0] #drop the .txt
name = filename.split("_")[0] #provided there's no underscore in the name part of the filename
year = filename.split("_")[1]
month = filename.split("_")[2]
day = filename.split("_")[3]
datestring = (month,day,year) # temp string to store a the tuple in the required order
date = "/".join(datestring) #as shown above
datestring = (year,month,day)
SQL_date = "-".join(datestring ) # SQL date
print name
print date
print SQL_date
Unless you want to use the datetime library to get the datetime date, in which case look up the datetime library
You can then do something like this:
SQL_date = datetime.strptime(date, '%m/%d/%Y')
This is the most explicit way I can think of right now. I'm sure there are shorter ways :)
Apologies for the bad formatting, I'm posting on mobile.

csv file to date format

I would like to read in a csv file of dates (shown below) and loop through it using solar.GetAltitude on each date to calculate a list of sun altitudes. (I'm using Python 2.7.2 on Windows 7 Enterprise.)
CSV file: TimeStamp 01/01/2014 00:10 01/01/2014 00:20 01/01/2014 00:30
01/01/2014 00:40
My code gives the following error ValueError: unconverted data remains:. This suggests the wrong date format, but it works fine on a single date, rather than a string of dates.
I've researched this topic carefully on Stack Overflow. I've also tried the map function, np.datetime64 and reading to a list rather than a string but get a different error referring to no attribute 'year'.
I'd really appreciate any help because I'm running out of ideas.
import datetime
from datetime import datetime
import julian
import solar
from solar import *
import os
import csv
# Create lists to hold the records.
dates = []
# Navigate to correct directory
os.chdir('D:\\Di_Python')
filename = 'SPA timestamp small.csv'
# Read through the entire file, skip the first line
with open(filename) as f:
# Create a csv reader object.
reader = csv.reader(f)
# Ignore the header row.
next(reader)
# Store the dates in the appropriate list.
for row in reader:
dates.append(row)
print row
# Change list to string so can use a function on it
lines = []
for date in dates:
lines.append('\t'.join(map(str, date)))
result = '\n'.join(lines)
print result
minutes = []
minutes.append(datetime.datetime.strptime(result,'%d/%m/%Y %H:%M'))
# Inputs
latitude_deg = 52.8
longitude_deg = -1.2
elevation = 0
# i should be 52560 - 10 min interval whole year
for i in minutes:
utc_datetime = i
altitude = solar.GetAltitude(latitude_deg, longitude_deg, utc_datetime)
altitude_list.append(altitude)
print altitude_list
First of all, the code is not indented properly making it harder to guess.
I think the input to datetime.datetime.strptime is not correct. You create result by using a '\n'.join(...) but the format string does not contain the '\n'. Creating a string from the list of dates seems unnecessary to me.
I think what you want is this:
for date in dates:
minutes.append(datetime.datetime.strptime(date, '%d/%m/%Y %H:%M'))
Note that the names you use for the lists are misleading as minutes holds datetime.datetime objects rather than minute values!
Many thanks to Vikramis and Lutz Horn for their help and comments. After experimenting with Vikramis' code, I achieved a working version which I have copied below.
My error occurred at line 40:
minutes.append(datetime.datetime.strptime(result,'%d/%m/%Y %H:%M'))
I found that I needed to create a string from the list to avoid the following error "TypeError: must be string, not list". I have now tidied this up by using (str(date) to replace the for loop and hopefully used more sensible names.
My problem was with the formatting. It needs to be
"['%d/%m/%Y %H:%M']" because I'm accessing items in a list, rather than "'%d/%m/%Y %H:%M'" which works in the shell for a single date.
import datetime
from datetime import datetime
import julian
import solar
from solar import *
import os
import csv
# Create lists to hold the records.
dates = []
datetimeObj = []
altitude_list = []
# Navigate to correct directory
os.chdir('D:\\Di_Python')
filename = 'SPA timestamp small.csv'
# Read through the entire file, skip the first line
with open(filename) as f:
# Create a csv reader object.
reader = csv.reader(f)
# Ignore the header row.
next(reader)
# Store the dates in the appropriate list.
for row in reader:
dates.append(row)
print row
# Change format to datetime
# str(date) used to avoid TypeError: must be string, not list
for date in dates:
datetimeObj.append(datetime.datetime.strptime(str(date),"['%d/%m/%Y %H:%M']"))
for j in datetimeObj:
print j
# Inputs
latitude_deg = 52.8
longitude_deg = -1.2
elevation = 0
# i should be 52560 - 10 min interval whole year
for i in datetimeObj:
utc_datetime = i
altitude = solar.GetAltitude(latitude_deg, longitude_deg, utc_datetime)
print altitude
altitude_list.append(altitude)
# print altitude_list

Is there a better way to delete files that are a month old in python?

I have built a script that generates files daily and names them by the date that they are generated. However, I then need to delete these files after 1 month, and have found it to be a bit confusing. I believe that the following will work, but I would like to know if Python has a built in feature that allows for this a bit more Pythonicly and elegently.
Note that this code handles files that are at the end of a month with more days than the following month by deleting all files from last month when it reaches the last day of this month.
if today.month != 1:
if today.day == days_in_month[today.month] and days_in_month[today.month] < days_in_month[today.month - 1]:
for x in range(days_in_month[today.month],days_in_month[today.month-1]+1):
date = date(today.year,today.month-1,x)
fname = str(date)+".stub"
remove(fname)
else:
date = date(today.year-1,12,x)
fname = str(date)+".stub"
remove(fname)
Take a look at Python's datetime module, it has some classes that should simplify this a lot. You should be able to create a datetime.datetime object from your file name using datetime.datetime.strptime(), and another for the current time using datetime.datetime.now(). You can then subtract one from the other to get a datetime.timedelta object that you can use to figure out the difference between the dates.
Rather than looking at the filenames to determine the age, you could use the creation time.
Something like:
import os
import datetime
path = "/path/to/files"
for file in os.listdir(path):
fullpath = os.path.join(path,file) # turns 'file1.txt' into '/path/to/file1.txt'
timestamp = os.stat(fullpath).st_ctime # get timestamp of file
createtime = datetime.datetime.fromtimestamp(timestamp)
now = datetime.datetime.now()
delta = now - createtime
if delta.days > 30:
os.remove(fullpath)

Categories