I was experimenting with something on Python and came across an interesting problem. I would like to enter the number of days and get the last and today's date in the range I specified. BUT, I only want the dates for the business days (Exclusing Holidays and Weekends). For example, I would like to do:
previous_days(10)
The output would give me the date that was 10 days ago and also today's date:
'2017-02-17' #10-days ago (because the 20th was President's day)
'2017-03-03' #Today's date
This is what I have been doing so far:
todaysDate = time.strftime("%Y-%m-%d") #outputs 2017-03-03
tenDaysAgo = datetime.strptime(todaysDate, "%Y-%m-%d").date() + timedelta(days=-12)
I had to do -12 to take into account the weekends. But the dates were incorrect this time because of President's day. Is there a library that exists in Python where I can enter the number of days I want and I can get the dates excluding weekends and holidays? If not, is there a more clever way for me to go about solving my issue?
Not enough reputation for a comment...
If DYZ's comment didn't help, take a look at dateutil.
More Dateutil examples
Other possibilities on SO here and here
Related
Let's assume that I have a list of dates like:
["2022-01-02", "2022-01-03"]
and so on. I also have a list of dates that are considered as a "holiday" in the same format. Now, I want to check if the dates from the first list cover the whole business week (so Monday to Friday), while taking the holiday list to consideration. So, if for example, I get provided with a list of days from Tuesday to Friday and there's no holiday on Monday then I'll get a False. But, if there would be a holiday on Monday, then I'd get a True.
Would be perfect if it worked between any two given dates, so that it won't be week-specific.
Is there any nice way of doing such things in python? How would you do it? Thanks in advance
Its a little difficult for me to exactly understand what you want, but I'll give you a head start and then you can tweak the if/else statements to your desire.
The datetime module has many features that might be of interest to you, including isofdateformat and isoweekday
The following code checks whether a day is a weekday and whether any of the days are holidays:
from datetime import date
# List of dates to check
dates = ["2022-01-04", "2022-01-05", "2022-01-06"]
# List of holidays
holidays = ["2022-01-03", "2022-01-06"]
# Convert the dates in the list to date objects
date_objects = [date.fromisoformat(d) for d in dates]
covers_week = True
for d in date_objects:
if d.isoweekday() not in range(1, 6):
# If any of the dates are not weekdays, the list does not cover a whole business week
covers_week = False
# Check if there are any holidays in the list
for d in date_objects:
if d in holidays:
# If there are any holidays in the list, the list does not cover a whole business week
covers_week = False
# Print result
print(covers_week)
I have a dataframe with bunch of dates in them, I would like to check each entry if it is a weekday or weekend, if it is a weekend i would like to increase the date to the next weekday. What is the most pythonic way of doing this ? I was thinking about using a list comprehension and s.th like
days = pd.date_range(start='1/1/2020', end='1/08/2020')
dates = pd.DataFrame(days,columns=['dates'])
dates['dates'] = [day+pd.DateOffset(days=1) if day.weekday() >4 else day for day in dates['dates']]
How could I adjust the code to cover day+pd.DateOffset(days=1) (for Sunday) and day+pd.DateOffset(days=2) (for Saturday) and get an updated column with the shifted dates? Running the code twice with +1 should work but is certainly not pretty
I am trying to add 148.328971 years precisely from the day 01.01.2000 using pandas. I first converted this to days by multiplying it by 365. So here is my question, albeit probably a dumb one.
Does pandas consider leap years when calculating days? The obvious answer is yes because it is calculating days but I have to make sure, precision of dates and time is important in the analysis I am trying to do.
I get this result when calculating with pandas which I am not sure is entirely correct:
03.25.2148 1:47:09 AM
code being used:
import pandas as pd
start = "01/01/2000"
end = pd.to_datetime(start) + pd.DateOffset(days=54140.074415)
print(end)
Any help would be greatly appreciated! Sorry in advance if this seems to be basic knowledge but I have to be certain
Your question is flawed, as stated; a year is not a fixed length of time. So what does "precisely 148.328971 years" even mean? Do you mean 148 calendar years plus 0.328971 of way through the next calendar year? And if you're counting down to a precision of 0.000001 year – a millionth of a year, or about 30 seconds – then "01.01.2000" is a pretty imprecise starting point; from what time on January 1st, 2000 are you counting?
Let's assume you mean civil calendar years from midnight UTC. Then 148.0 years would get you to January 1, 2148, still at midnight UTC. Since 2148 is a leap year, 0.328971 of the way through it would add 0.328971 × 366 = 120.403 more days, which gets you to April 30, 2148 at 09:40 UTC.
Maybe you mean to be counting some "year" value that really is fixed? We do that in other contexts; the light year is based on the mean Julian calendar year, and so is defined as the distance light travels in exactly 365.25 atomic days. If you mean 148.328971 of those years, that'd be 54,177.1567 days, which would get you to May 1, 2148 at 03:45 UTC instead.
But we don't use the Julian calendar anymore for civil purposes. Maybe you want instead the mean year of the Gregorian calendar, which replaced it in the West? That's exactly 365.2425 days; 148.328971 of those years is 54,176.0442 days, from 2000 Jan 1 is back to 2148 April 30, only now at 01:03 UTC.
Then again, In parts of the world where the Eastern Orthodox Church is dominant, they instead use the Revised Julian calendar, whose mean year is 365.242̅ days (exactly 365 days, 5 hours, 48 minutes, 48 seconds). 148.328971 of those years is only 54,176.0030 days, which still get you to April 30th, but just barely over the line from the 29th at less than 5 minutes after midnight: 00:04 UTC.
So if you're counting calendar years of some description, you wind up somewhere on April 30th or May 1st, 2148. I trust this is helpful.
But maybe you mean to toss out calendars and go directly to the value they're trying to approximate: the mean tropical year! But then we have to ask where in the year you're measuring from, because December solstice to December solstice is a different length on average than March equinox to March equinox (because the length of the year itself is constantly changing). When we need a fixed value we tend to use the average of averages, as it were, taking the mean of the length values across the whole year. As of 2000 that value was about 365.24219 days. 148.328971 of those is only 54,175.9982 days, which leaves you even earlier: April 29th, 2148 at 23:57 UTC.
Then there's the sidereal year, but even though it arguably has the greatest claim at being the "real" period of the Earth's orbit, it doesn't see much use outside astronomy; probably not that.
Anyway, the real question is - where does this "148.328971" figure come from, and what is the intent behind it? Once you know what the desired answer actually is, it will be easy enough to find its value.
Yes, it does. However, your conversion from years to days is already ignoring the leap years. You can multiply by 365.25 (365.242, as suggested in the comments) which gives better results.
You can check the accuracy of the results on wolfram alpha: https://www.wolframalpha.com/input/?i=148.328971+years++from+01%2F01%2F2000
In addition, you can use pandas DateOffset with years. However, currently only integer values are supported.
import pandas as pd
start = "01/01/2000"
end = pd.to_datetime(start) + pd.DateOffset(years =148, days =0.328971*365.242)
print(end)
# 2148-04-30 03:45:35.229600
It seems to work well but misses by few hours.
I am trying to convert a dataframe column with a date and timestamp to a year-weeknumber format, i.e., 01-05-2017 03:44 = 2017-1. This is pretty easy, however, I am stuck at dates that are in a new year, yet their weeknumber is still the last week of the previous year. The same thing that happens here.
I did the following:
df['WEEK_NUMBER'] = df.date.dt.year.astype(str).str.cat(df.date.dt.week.astype(str), sep='-')
Where df['date'] is a very large column with date and times, ranging over multiple years.
A date which gives a problem is for example:
Timestamp('2017-01-01 02:11:27')
The output for my code will be 2017-52, while it should be 2016-52. Since the data covers multiple years, and weeknumbers and their corresponding dates change every year, I cannot simply subtract a few days.
Does anybody have an idea of how to fix this? Thanks!
Replace df.date.dt.year by this:
(df.date.dt.year- ((df.date.dt.week>50) & (df.date.dt.month==1)))
Basically, it means that you will substract 1 to the year value if the week number is greater than 50 and the month is January.
I'm looking for an easy way to get the current week number of the year in Python. I'm well aware of the datetime.datetime.isocalendar() function in the standard library, but this function stipulates that week 1 is the first Monday of the new year. My dilemma is that I'm using Sunday as a starting point for each week, and if Sunday is for example December 27 and January 1st appears at some point during that week, I need to represent that week as week 1 (and year 2015).
I thought of doing something like (pseudocode):
if (Jan 1) - (current_sunday) < 7 days:
week_num = 1
And then storing that week number somewhere to iterate over next week. However, I feel that this is a very hackish method and would prefer something cleaner.
Generally to get the current week number (starts from Sunday):
>>> import datetime
>>> import calendar
>>> today = datetime.date.today())
>>> (int(today.strftime('%U')) + (datetime.date(today.year+1, 1, 1).weekday() != calendar.SUNDAY)) % 53
12
From the documentation of strftime('%U'):
"Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0."
Hence the modified code for your specific requirements. There isn't really a non-hacky way to do what you want.