Extracting data from pyephem date string in Python - python

I want to extract the sunrise hour and if I do the following
sun = ephem.Sun()
r1 = home.next_rising(sun)
print ("Visual sunrise %s" % r1)
risehr = r1[10:12]
print ("Rise Hour = %s" % risehr)
I got the error
>>'ephem.Date' object has no attribute '__getitem__'
I can print the string r1 but not extract from it (?)
I tried solutions from similar problem posts on extraction but couldn't make any progress, apologies if this appears to be a double post.

As I understand your question you want to print only hour of sunrise. r1 is object of ephem.Date type. You could make it with brute force
...
risehr = str(r1)[10:12]
...
or you could convert r1 object to datetime, and datetime to str representation
...
risehr = r1.datetime().strftime('%H')
...
or convert it to tuple first
...
risehr = r1.tuple()[3]
...
All available options you could read at this page in section Conversions.

#kvorobiev answered the question of how to extract from a string representation of your data. But the other half of your question was the error:
'ephem.Date' object has no attribute '__getitem__'
According to the PyEphem documentation for the next_rising() function,
If the search is successful, returns a Date value.
Furthermore, Date objects have an important property:
Dates are stored and returned as floats. Only when printed, passed to str(), or formatted with '%s' does a date express itself as a string giving the calendar day and time.
When you gave the command risehr = r1[10:12], the Python interpreter attempted to get call Date.getattr() to get the fields from a Date object corresponding to the slice 10:12. Without that method, slicing has no meaning to a Date object.
But all is not lost! You can still get the Date object's time information:
Call .tuple() to split a date into its year, month, day, hour, minute, and second.
You can then slice this tuple as needed to get the hour:
hour = r1.tuple()[3]
Or exhaustively:
year, month, day, hour, minute, second = r1.tuple()

Related

Using Pandas .apply() method with a regex-based function

I am trying to create a new column in a data Frame by applying a function on a column that has numbers as strings.
I have written the function to extract the numbers I want and tested it on a single string input and can confirm that it works.
SEARCH_PATTERN = r'([0-9]{1,2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})'
def get_total_time_minutes(time_col, pattern=SEARCH_PATTERN):
"""Uses regex to parse time_col which is a string in the format 'd hh:mm:ss' to
obtain a total time in minutes
"""
days, hours, minutes, _ = re.match(pattern, time_col).groups()
total_time_minutes = (int(days)*24 + int(hours))*60 + int(minutes)
return total_time_minutes
#test that the function works for a single input
text = "2 23:24:46"
print(get_total_time_minutes(text))
Ouput: 4284
#apply the function to the required columns
df['Minutes Available'] = df['Resource available (d hh:mm:ss)'].apply(get_total_time_minutes)
The picture below is a screenshot of my dataframe columns.
Screenshot of my dataframe
The 'Resources available (d hh:mm:ss)' column of my dataframe is of Pandas type 'o' (string, if my understanding is correct), and has data in the following format: '5 08:00:00'. When I call the apply(get_total_time_minutes) on it though, I get the following error:
TypeError: expected string or bytes-like object
To clarify further, the "Resources Available" column is a string representing the total time in days, hours, minutes and seconds that the resource was available. I want to convert that time string to a total time in minutes, hence the regex and arithmetic within the get_total_time_minutes function. – Sam Ezebunandu just now
This might be a bit hacky, because it uses the datetime library to parse the date and then turn it into a Timedelta by subtracting the default epoch:
>>> pd.to_datetime('2 23:48:30', format='%d %H:%M:%S') - pd.to_datetime('0', format='%S')
Out[47]: Timedelta('1 days 23:48:30')
>>> Out[47] / pd.Timedelta('1 minute')
Out[50]: 2868.5
But it does tell you how many minutes elapsed in those two days and however many hours. It's also vectorised, so you can apply it to the columns and get your minute values a lot faster than using apply.

Compare WebElement with Timedelta

i have a HTML Table with 5 columns. In the third column are links and in the fifth column is a Date.
Now i want to write a code which check if the date is within the next 4 weeks and if yes, then click on the link
This is what i have so far:
# Set the Date
start = time.strftime('%d-%m-%Y')
now = datetime.datetime.strptime(start, '%d-%m-%Y')
date_in_four_weeks = now + datetime.timedelta(days=28)
project_time = date_in_four_weeks - now
# Check the date and click on link
for i in range(project_time.days + 1):
print(now + timedelta(days=i))
time = driver.find_element_by_css_selector('css_selector')
if time <= project_time:
linkList = driver.find_elements_by_css_selector("css_selector")
for i in range(0,len(linkList)):
links = driver.find_elements_by_partial_link_text('SOLI')
links[i].click()
driver.get_screenshot_as_file("test.png")
else:
print "No Project found"
If i run the code i get the error:
TypeError: can't compare datetime.timedelta to WebElement
Now i want to ask if there is any way how i can fix my problem?
Thanks :)
There's a few issues you have to address.
Firstly, you're comparing to a WebElement object, as the error helpfully points out. This includes the tags and such of the HTML element you're referencing. You first want to extract the text.
Then, you need to parse this text to convert it into a Python datetime or date object. A time object won't do because it only stores time, and not date. Since I don't know what format your HTML date is in, I'll just point you to the docs so you can see how the types work and have some idea of how to parse your data.
Finally, you'd still get an error because of trying to compare a timedelta object to a date or datetime object. A timedelta is a period of time, it doesn't relate to a specific date.
You could fix this by replacing
if time <= project_time:
With the same as from your print function:
if time <= now + timedelta(days=i)

Python dateutil date conversion

I'm trying to see if a list of dates are valid dates. I'm using the dateutil library, but I'm getting weird results. For example, when I try the following:
import dateutil.parser as parser
x = '10/84'
date = (parser.parse(x))
print(date.isoformat())
I get the result 1984-10-12T00:00:00 which is wrong. Does anyone know why this 12 gets added to the date?
The parse() method parses the string and updates a default datetime object, using the parsed information. If the default is not passed into this function, it uses first second of today.
This means that the 12 in your result, is today (when you're running the code), only the year and the month are updated from parsing the string.
If you need to parse the date string but you're not sure if it's a valid date value, then you may use a try ... except block to catch parse errors.
import dateutil.parser as parser
x = '10/84'
try:
date = (parser.parse(x))
print(date.isoformat())
except ValueError as err:
pass # handle the error
12 is the current date . dateutil takes components from current date/time to account for missing date or year in the date (it does not do this for the month, only date or year). Like another example would be a date like - Janauary 20 - this would get parsed as 2015/01/12 taking the 2015 year from the current datetime.
Sadly I have not yet found any options or such to stop this behavior.
I believe the best option for you would be to come up with a list of the valid datetime formats that you are expecting , and then manually try datetime.datetime.strptime on them , excepting ValueError . Example -
def isdate(dt, fmt):
try:
datetime.datetime.strptime(dt, fmt)
return True
except ValueError:
return False
validformats = [...]
dates =[...]
for x in dates:
if any(isdate(x,fmt) for fmt in validformats):
print(x, 'is valid date')

How to convert integer into date object python?

I am creating a module in python, in which I am receiving the date in integer format like 20120213, which signifies the 13th of Feb, 2012. Now, I want to convert this integer formatted date into a python date object.
Also, if there is any means by which I can subtract/add the number of days in such integer formatted date to receive the date value in same format? like subtracting 30 days from 20120213 and receive answer as 20120114?
This question is already answered, but for the benefit of others looking at this question I'd like to add the following suggestion: Instead of doing the slicing yourself as suggested in the accepted answer, you might also use strptime() which is (IMHO) easier to read and perhaps the preferred way to do this conversion.
import datetime
s = "20120213"
s_datetime = datetime.datetime.strptime(s, '%Y%m%d')
I would suggest the following simple approach for conversion:
from datetime import datetime, timedelta
s = "20120213"
# you could also import date instead of datetime and use that.
date = datetime(year=int(s[0:4]), month=int(s[4:6]), day=int(s[6:8]))
For adding/subtracting an arbitary amount of days (seconds work too btw.), you could do the following:
date += timedelta(days=10)
date -= timedelta(days=5)
And convert back using:
s = date.strftime("%Y%m%d")
To convert the integer to a string safely, use:
s = "{0:-08d}".format(i)
This ensures that your string is eight charecters long and left-padded with zeroes, even if the year is smaller than 1000 (negative years could become funny though).
Further reference: datetime objects, timedelta objects
Here is what I believe answers the question (Python 3, with type hints):
from datetime import date
def int2date(argdate: int) -> date:
"""
If you have date as an integer, use this method to obtain a datetime.date object.
Parameters
----------
argdate : int
Date as a regular integer value (example: 20160618)
Returns
-------
dateandtime.date
A date object which corresponds to the given value `argdate`.
"""
year = int(argdate / 10000)
month = int((argdate % 10000) / 100)
day = int(argdate % 100)
return date(year, month, day)
print(int2date(20160618))
The code above produces the expected 2016-06-18.
import datetime
timestamp = datetime.datetime.fromtimestamp(1500000000)
print(timestamp.strftime('%Y-%m-%d %H:%M:%S'))
This will give the output:
2017-07-14 08:10:00

Attempting to insert an integer from a list into datetime object

What I am trying to accomplish is very simple: creating a loop from a range (pretty self explanatory below) that will insert the month into the datetime object. I know %d requires an integer, and I know that 'month' type is int...so I'm kind of stuck as to why I can't substitute my month variable. Here is my code:
all_months=range(1,13)
for month in all_months:
month_start = (datetime.date(2010,'%d',1))%month
next_month_begin= datetime.date(2010,'%d',1)%(month+1)
month_end=next_month_begin - timedelta(days=1)
print month_start
print month_end
What am I doing wrong?
All help appreciated! Thanks
There are a few things that you need to fix here.
EDIT: First, be careful with your range, since you are using month+1 to create next_month_begin, you do not want this to be greater than 12 or you will get an error.
Next, when you are trying to create the date object you are passing the month in as a string when you use (datetime.date(2010,'%d',1))%month. Your code probably throwing this error TypeError: an integer is required.
You need to give it the integer representing the month, not a string of the integer (there is a difference between 1 and '1'). This is also a simple fix, since you have variable named month that is already an integer, just use that instead of making a string. So you code should be something like:
month_start = datetime.date(2010,month,1)
I think you can figure out how to apply this to your next_month_begin assignment.
The last problem is that you need to use datetime.timedelta to tell Python to look in the datetime module for the timedelta() function -- your program would currently give you an error saying that timedelta is not defined.
Let me know if you have any problems applying these fixes. Be sure to include what the error you may be getting as well.
You've got other answers, but here's a way to get the last day of the month. Adding 31 days will get you into the next month regardless of the number of days in the current month, then moving back to the first and subtracting a day will give the ending date.
import datetime
for month in range(1,13):
month_start = datetime.date(2010,month,1)
into_next_month = month_start + datetime.timedelta(days=31)
month_end = into_next_month.replace(day=1) - datetime.timedelta(days=1)
print month_start,month_end
month is a variable and you can use it to create the datetime object. I think you want to do the following:
month_start = datetime.date(2010, month, 1)
next_month_begin = datetime.date(2010, month+1, 1)
That will work, because datetime.date() requires 3 integer arguments. '%d' % month would instead format the integer month as string. '%04d' % 3 for example would format the number 3 with 4 digits and leading zeros. But it's important to know, that even the (nearly unformatted) string "3" is different to the number 3 in Python.
And you can't write datetime(...) % 3 because the % operator will only work when used on a format string like the previous "%03d" % 3 example and not on a datetime object.
But other types might also accept the % operator (not including datetime objects). For example, integers accept the % operator to get the remainder of a division: 3 % 2 # returns 1. But there, the meaning of % is completely different, because the meaning of the operator depends on the types involved. For example, try 3 + 2 and "3" + "2". There, the meaning of + differs (integer addition vs. string concatenation), because the types are different too.
Check out the calendar module (http://docs.python.org/library/calendar.html).
It has batteries included for this sort of thing...
You could just do:
from calendar import Calendar
def start_and_end_days(year, month):
cal = Calendar()
month_days = [day for day in cal.itermonthdays(year, month) if day.month == month]
first_day = month_days[0]
last_day = month_days[-1]
return (first_day, last_day)

Categories

Resources