Select Distinct Years and Months for Django Archive Page - python

I want to make an archive_index page for my django site. However, the date-based generic views really aren't any help. I want the dictionary returned by the view to have all the years and months for which at least one instance of the object type exists. So if my blog started in September 2007, but there were no posts in April 2008, I could get something like this
2009 - Jan, Feb, Mar
2008 - Jan, Feb, Mar, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
2007 - Sep, Oct, Nov, Dec

This will give you a list of unique posting dates:
Posts.objects.filter(draft=False).dates('post_date','month',order='DESC')
Of course you might not need the draft filter, and change 'post_date' to your field name, etc.

I found the answer to my own question.
It's on this page in the documentation.
There's a function called dates that will give you distinct dates. So I can do
Entry.objects.dates('pub_date','month') to get a list of datetime objects, one for each year/month.

You should be able to get all the info you describe from the built-in views. Can you be more specific as to what you cannot get? This should have everything you need:
django.views.generic.date_based.archive_month
Reference page (search for the above string on that page)

Related

Why do my files have a last modified timestamp of January 1, 1980?

I'm working in Python with a number of libraries at play.
I have a group of files on a Linux server that have the last modified timestamp of midnight on January 1, 1980 (unix timestamp 315532800.0). The last changed timestamp however is recent. What could have caused this?
In particular, Jan 1 1980 is a suspiciously round number, but not one of the usual suspicious round numbers.
The culprit is the Python zipfile library. If you don't pass a second parameter to ZipInfo, it defaults to Jan 1, 1980: https://docs.python.org/3/library/zipfile.html#zipfile.ZipInfo

Convert relative time in words into formatted date format in python

How to convert relative time that are expressed in humanised words like "-100 days, -6 months, -1 year, +1 year" into YYYY-MM-DD format?
I am posting my answer to help others if they need the same thing.
What I am doing is developing a CLI application, part of the process is user will input starting date and end date, but I want the user to use a relative time like the following:
(for the sake of a an example date, October 23, 2017 would be the current date)
$ cliapp.py --start_time="10 days ago" --end_time="yesterday"
10 days ago is "2017-10-13"
yesterday is "2017-10-22"
$ cliapp.py --start_time="tomorrow"
tomorrow is "2017-10-24"
to accomplish this I found dateparser module and works exactly what I need.
here is the link to it: https://dateparser.readthedocs.io/en/latest/
If you have other solution, feel free to put on comment. :)

Parsing human-readable recurring dates in Python

The problem. In my Django application, users create tasks for scheduled execution. The users are quite non-technical, and it would be great if they can write conventional human-readable expressions to define when to execute certain task, such as:
every monday
every fri, wed
daily
1, 14, 20 of each month
every fri; every end of month
This is inspired by Todoist. For now, only dates are necessary; no times. I've spent a couple of hours googling for a library to do that, but with no luck. I am expecting a function, say, in_range(expression, date), such that:
>>> in_range('every monday, wednesday', date(2014, 4, 28))
True
>>> in_range('every end of month', date(2014, 5, 12))
False
>>> in_range('every millenium', date(2014, 5, 8))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: unknown token "millenium".
Variants. That's what I've looked through.
Standard datetime library does date parsing, but not date range parsing as per above.
Python-dateutil - supports recurring dates via rrule, very functional, but still does not support parsing.
Python-crontab and Python-croniter accept standard Unix crontab syntax (and allow to specify weekdays, etc), but still such syntax is a way too technical and I'd like to avoid it if possible.
Arrow and Parsedatetime do not support the feature.
So, is there a Python code snippet, or a library that I missed, to do the thing? If not, I'm going to write the parser myself. Would like to release it in open source if it appears to be not too bad.
Recurrent is a library that will do natural language date parsing with support for recurring dates. It doesn't match the API you provided, but allows you to create rules that can be used with Python's datetime library.
From their Github page:
Natural language parsing of dates and recurring events
Examples
Date times
next tuesday
tomorrow
in an hour
Recurring events
on weekdays
every fourth of the month from jan 1 2010 to dec 25th 2020
each thurs until next month
once a year on the fourth thursday in november
tuesdays and thursdays at 3:15
Messy strings
Please schedule the meeting for every other tuesday at noon
Set an alarm for next tuesday at 11pm

This specific str.replace() in Python with BeautifulSoup isn't working

I'm trying to automate a task that occurs roughly monthly, which is adding a hyperlink to a page that looks like:
2013: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2012: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2011: Jan Feb Mar ...
Whenever we get a new document for that month, we add the
Jul
tags around it.
So I'm using BeautifulSoup in Python. You can see below that I'm picking out the HTML "p" tag that contains this data and doing a replace() on the first month that it finds (finds Month using the reverse dictionary I created, and the third parameter of replace() indicates to only do the first one it finds).
# Modify link in hr.php:
hrphp = open('\\\\intranet\\websites\\infonet\\hr\\hr.php', 'r').read()
soup = BeautifulSoup(hrphp) # Parsing with BeautifulSoup
Months = {k: v for k,v in enumerate(calendar.month_abbr)} # Creates a reverse dictionary for month abbreviation lookup by month number, ie. "print Months[07]" will print "Jul"
print hrphp+"\n\n\n\n\n" # DEBUGGING: Compare output before
hrphp = hrphp.replace(
str(soup.findAll('p')[4]),
str(soup.findAll('p')[4]).replace(
Months[int(InterlinkDate[1][-5:-3])],
""+Months[int(InterlinkDate[1][-5:-3])]+"",
1),
1
)
print hrphp # DEBUGGING: Compare output after
See how it's a nested replace()? The logic seems to work out fine, but for some reason it doesn't actually change the value. Earlier in the script I do something similar with the Months[] dictionary and str.replace() on a segment of the page, and that works out, although it doesn't have a nested replace() like this nor does it search for a block of text using soup.findAll().
Starting to bang my head around on the desk, any help would be greatly appreciated. Thanks in advance.
What you end up doing with the code str(soup.findAll('p')[4]).replace is just replacing the values that are found in a string representation of the results in soup.findAll('p')[4], which will more than likely differ from the string in hrphp because "Beautiful Soup gives you Unicode" after it parses.
Beautiful Soups documentation holds the answer. Have a look at the Changing Attribute Values section.

Looking for *existing* Python module for determining fiscal months

I'm in calendar hell, and I'm hoping there exists a Python module out there that does what I want.
I'm making a Python web app that deals with subscriptions. It's conceptually similar to a cell phone plan: You start your subscription on a certain date (say 1.13.2011), and for every billing month you have a bunch of "sessions" (phone calls), that you would be charged for.
We need to:
Know under which billing month each session falls.
Know the start time and end time of each billing month.
For example, if you signed up on 1.13.2011, and made a phone call on 1.20.2011, it would count on your first billing month. Same for a phone call on 2.10.2011. But if you were to make a phone call on 2.15.2011, it will count on your second billing month.
Regarding start and end dates: If today is 2.15.2011, then the start date of the current month is 2.13.2011 and its end date is 3.13.2011.
You may be thinking this is not so complicated, but then you have to consider that months have different lengths. The rule for handling this is that if your subscription started on the 30th of whatever month, its cutoff dates on each month would be min(30, n_days_in_that_month). This goes for 29, 30 and 31 as well.
I tried coding this, but it got too complex. What I'm looking for is a ready-made, existing module that does these things.
For the love of God don't post an answer with a sketch of an implementation! This is useless for me. I appreciate your intentions, but in calendar hell, sketches of implementations do not help. I already have a sketch of an implementation, and debugging yours will take just as long as debugging mine.
I am only interested in using an existing module that handles such calendar tasks. Do you know one?
http://labix.org/python-dateutil
Ram's edit: The dateutil.rrule.rrule class is the one that did exactly what I wanted.
Regarding start and end dates: If today is 2.15.2011, then the start date of the current month is 2.13.2011 and its end date is 3.13.2011.
You may be thinking this is not so complicated, but then you have to consider that months have different lengths. The rule for handling this is that if your subscription started on the 30th of whatever month, its cutoff dates on each month would be min(30, n_days_in_that_month). This goes for 29, 30 and 31 as well.
Its still pretty basic. Use datetime module to store datetimes, so you can easily parse out the day (e.g., if dt is a date then dt.day). A billing cycle starts on say the 29th (toughest type of case). Let billing_cycle_day=29. A billable event occurs on say the event_day=10, event_month=5. Then since event_day < billing_cycle_day you bill to event_month's bill. Otherwise you bill to the next months bill (remembering that if month=12; you have to increment the year).
So now the billing cycle will always be from the 29th to the 28th in the next month. The complication arises if say a date like 2/29/2011 doesn't exist. E.g., a billing cycle start_date should be 2/29/2011 (but it doesn't exist); in this case you just make it the first on the next month.
billing_cycle_day = 29
year, month = 2011, 2
import datetime
def create_date_or_first_of_next_month(year, month, day):
try:
return datetime.date(year, month, day)
except ValueError:
year_n, month_n = (year, month+1) if month != 12 else (year+1, 1)
return datetime.date(year_n, month_n, 1)
This problem is not as hard as you think. All you have to do is write a function that given a starting day (like 13 or 30) it returns two date objects which are the beginning and end of the current fiscal month. You have already sketched out all the details in your question. Best to include an optional todayis parameter to the function so that you specify what day to use as a reference for today. For instance, if today is the 15th of October 2011, and you specify 13, the function would assume that you mean the 13th of October 2011. But if you want to rerun June data, you would specify todayis=date(2011,06,13)
The return values (start and end) allow you to pinpoint dates that belong in this fiscal month. But if the date is before the start date and less than 29 days before the start date, then you can also pinpoint in the previous fiscal month. The same goes for the next fiscal month. This is useful because there will be a lot of situations where you process data after a few days, so you will have a mix of two fiscal months to process.

Categories