#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    12
    Rep Power
    0

    Time Clock program help.


    Hey all.

    I am wanting to write a time tracking program in python.

    It will be a small window with just a display of "time passed" on it. When you click on it, it expands to show an interface for entering the company worked for, the current project, and a description of what was done on the project. The first two entry fields will be entry fields as well as a drop down that stores recent projects and companies.

    You can start, stop, and pause a project.

    When you stop the project, I want it to automatically save the company, project, project description, time started, time ended, and time spent to an excel compatible file.

    When you first run the program, it will ask you what directory you want to save the files to.
    Within this folder, it will create folders by year and the files themselves will be created by month.

    I have learned the basics of programming with python and I understand the fundamentals of programming and OOP.

    My questions are:

    How do you know when to make a module a separate file?

    Do you have any suggestions as to how I can do any of the stuff mentioned above? I want to do the coding myself since this is a way for me to learn more about python and programming. Are there any sites or resources I can go to that will help me?

    I hope I'm not out of line in asking these questions.

    Thanks for reading and thanks for your suggestions!

    Zach
  2. #2
  3. Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2012
    Location
    39N 104.28W
    Posts
    158
    Rep Power
    3
    Originally Posted by zkirkland
    Hey all.

    I am wanting to write a time tracking program in python.

    It will be a small window with just a display of "time passed" on it. When you click on it, it expands to show an interface for entering the company worked for, the current project, and a description of what was done on the project. The first two entry fields will be entry fields as well as a drop down that stores recent projects and companies.

    You can start, stop, and pause a project.

    When you stop the project, I want it to automatically save the company, project, project description, time started, time ended, and time spent to an excel compatible file.

    When you first run the program, it will ask you what directory you want to save the files to.
    Within this folder, it will create folders by year and the files themselves will be created by month.

    I have learned the basics of programming with python and I understand the fundamentals of programming and OOP.

    My questions are:

    How do you know when to make a module a separate file?

    Do you have any suggestions as to how I can do any of the stuff mentioned above? I want to do the coding myself since this is a way for me to learn more about python and programming. Are there any sites or resources I can go to that will help me?

    I hope I'm not out of line in asking these questions.

    Thanks for reading and thanks for your suggestions!

    Zach
    My $.02:
    a. I would start with all the pieces in a single file. If and when you find that any classes or functions are more generally useful, then you can move them to their own module file.

    b. It sounds like you are planning to use a GUI (rather than a terminal interface). I recommend saving that part for last and building the actual computing parts first. As for that, I'm not sure exactly what "displaying time passed" might be, just a counter? Anyway, play around with entering data and doing something with it. I think you'll find out what you need to do and if not, return with specific questions.
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    12
    Rep Power
    0
    Thanks for the reply!

    I will do as you suggest with the modules.

    Yes, I was talking about a counter. When you start the project, it starts counting up in "00:00:00" format (hours:minutes:seconds).

    When you stop it, the timer will reset itself...(I think...not sure yet if I want it to stay until a new project is started or not...)

    Zach
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Location
    Usually Japan when not on contract
    Posts
    240
    Rep Power
    12
    Originally Posted by zkirkland
    When you stop it, the timer will reset itself...(I think...not sure yet if I want it to stay until a new project is started or not...)
    Don't worry about whether it resets itself or not just yet, or if it stays or not. Those are interface questions, really, not core functionality questions.

    If this application is attaching itself to a database then half of your work is already done (I'm sweet on Postgres, but nearly any database has the features you need). If not, then you need to do two things before anything else:
    1- Determine how you want to store your data and where (in files? are they shared across users or just local?)
    1.1- If local I strongly recommend using yaml instead of your own custom parsing or diving into the insanity of XML.
    1.2- If shared I strongly recommend using a database backend like Postgres via bindings like psycopg.
    2- Determine how you are going to accumulate time over projects: Will you record start/stop/interval totals, just interval totals, or just start/stop and then accumulate your result when needed?
    2.1- The right answer depends on how you are going to store data, what you might possibly want to know about events happening today three years from now (could you be audited for billing performance and need more than just the interval totals? a report log?) and whether storage space or processing power is more plentiful to you
    2.2- In most cases both are abundant, and storing all three along with a "cleaning" routine that can be run whenever desired to verify that the intervals are sane based on the starts and stops, etc. (once again, using a database makes a lot of this automatic for you.)

    Once you make decisions based on the above, write a textual version of your program. It needs to be able to record projects (just basic identifiers are OK for now), start times and stop times and save them in a sane way. Then see if you can write a function that diffs the starts/stops and produces an interval for each entry. Then see if you can write another function that calls the first and sums the result. Then see if you can modify that one to pull only the project times of the project you specify. Then write another one that calls that last one and displays projects you specify.

    Up to this point writing any classes/objects is probably not a good idea. The task is up to now just arguments in, results out, a touch of file or db I/O. Way easier to move things around and think about just functions here.

    But after the text version does what you want, you will want to write a GUI with PyQt/PySide or PyGTK or whatever to make widgets and buttons and your nice clock display that knows to reset when a button is pushed. This is where the OOP stuff comes in handy.

    Blah blah blah. Been drinking, so please forgive typos. Have fun with this. You'll learn a lot. This is a great stepping-stone application for a hacker, actually: its small, well defined, contains a lot of things you haven't done before, and you seem to personally care about the outcome. After writing this, you'll be capable of writing nearly anything given enough time to think things through.
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    12
    Rep Power
    0
    I will be saving the file to wherever the person wants to save the file.

    I will be using yaml or something similar to handle the xml.

    As stated in my original post, I will be recording the start time, stop time, and time difference.

    Within the folder the user chooses, the program will create a folder for whatever the current year is, and then in that folder it will create an xml file that contains the data for the current month.

    This data will be:
    Current date
    Company the project is for
    The project that is being worked on
    A description of what you did on this project
    Start time
    End time
    Total time spent on the project

    With the "total time spent", the program should look to see if a project with that name already exists for the current day. If it does not exist, it creates one but if the project already exists, it will add the amount of time spent on the project to the existing data in the xml file instead of creating a duplicate entry.

    I have written out an outline of what functions I want and I have a diagram that I did with a mind mapping program to help me see how the modules interact with each other.

    Thanks for the info and I will follow your advice!
    Zach
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Location
    Usually Japan when not on contract
    Posts
    240
    Rep Power
    12
    Strip all this down to the bare bits for right now. Forget about XML, letting users pick file locations and file locations (one file is big enough for right now).

    Can you conceive of your data as a series of basic Python structs (dicts, tuples, lists, sets)? If so, then you're ahead of the game. Its all about structure right now -- the functions you need to write will be obvious once you decide the shape of your data.

    You mentioned that you don't want duplicates per day. People working on their first calendar application often say something like this (and then never do again). Here are some issues to think over before you say that you don't want to store duplicate day entries per project (which is a totally different issue from outputting duplicate days to the user):

    1- How are you going to enforce that? The data here is inherently relational in nature but isn't going to be represented that way outside of an RDBMS. You can conjure up a system arbitrary procedural constraints which will need to run each time data is updated, create a procedure where dict keys can only be generated from a set() list, or get all typical/ridiculous and create a village full of object classes that pretend to do things that are really just functions disguised as method, or venture even deeper into unmaintainable territory and make every idea you can think up into its own object class (bonus points for needless multiple and cross-inheritance).

    2- If you can't have duplicate days, does that also mean you need to have every day? Usually its hard to force unique existence of things that occur in natural sequence (dates being particularly tricky) without also deciding that you must include every member of that sequence. This might suck since you don't need 365.25*years*projects worth of days.

    3- What happens when someone works past midnight? Do we detect this and cut the previous day at midnight and start a new entry for the next day, or do we wait until its time to save and then split it? How do we mark how long was worked for that span? Later, when checking for duration of a single session (trying to discover worker averages, for example) do we arbitrarily check whether it ended at midnight, and if so also check if there is a matching start the next day at 00:01? Hmmm... we already have several needs for special case checking -- maybe not good.

    Instead of saying "no duplicate dates in the base data" I'd recommend storing the interval bounds and the distance between them but forget about any other rules that "start > stop" when it comes to raw data storage.

    Processed data is a totally different thing, though. You can take your raw facts and generate a separate, updatable set of data outputs that represent anything whatever way you can dream up (no duplicate dates if you're viewing days, workers if viewing workers, projects if viewing projects. etc.). Don't get confused between what is a raw fact ("an event happened of type X from Y to Z") and what is a processed answer to a human question ("How long did Tom work last Tuesday?").

    Another point: How are you going to index your companies and projects? Does each one have a code or something unique by which it can be referenced? A textual representation of the name is sometimes not enough. This is an issue that can sneak up on you once you encounter real world data ("FourBucks, Inc." and "FourBucks, Co. LTD", identical names of natural persons who may be clients or identical company names across state/national boundaries). This is why every accounting section I've ever seen had some sort of encoding system for each customer, supplier and worker of economic interest to the operation. Sometimes copying their code system simplifies life (and sometimes not -- the point is there is usually already some system that addresses the uniqueness problem you can mimic).

    A lot of the issues above can be automagically solved by using a decent RDBMS (they are designed specifically to manage these issues), but that's not always an option. You're going to find that you will soon implement a mini-version of a special-purpose RDBMS in Python due to the nature of your data. Not such a big deal, but its a lot of extra effort when a tool specially designed to make this sort of problem managable is already available. (Also, decent RDBMSs are way faster at finding stuff and generating reports...)

    XML is a burdensome complication -- which is why I recommend YAML (every language I know of has libraries for both; no hazard there). YAML looks like nested lists, which fits Python perfectly and makes generation/editing of source documents easy. YAML has the huge benefit of already looking nearly like Python dicts, lists and tuples, so you don't need any wacky DOM manipulations to do something simple like load your base data, since yaml.load() returns Python objects directly. If your boss is forcing you at gunpoint to use XML, prototyping in YAML will save you a lot of time by letting you not think about your XML schema or the details of whatever XML library you choose to use while you get the actual program to function properly.

    Notice this whole time the only issue I've really addressed is you data design. I can't emphasise enough that once you decide how your data is going to be structured then your basic functionality will almost write itself.
    [code=python]
    cust_data = [{'customer': 'Lungbrush, Inc.',
    'projects': ['Brushchecker 1.0']},
    {'customer': 'Foomatic.com',
    'projects': ['Fooz 2.0', 'Bazzuz 1.0']}]
    workers = ['Tom', 'Bill', 'Jane']
    performance = [{'project': ('Foomatic.com', 'Fooz 2.0'),
    'worker': 'Jane',
    'times': (datetime(start), datetime(end), duration)}][/code]
    or
    [code=yaml]
    ---
    #Customer data
    cust_data
    -
    customer: Lungbrush, Inc.
    projects:
    - Brushchecker 1.0
    -
    customer: Foomatic.com
    projects:
    - Fooz 2.0
    - Bazzuz 1.0
    ---
    # Worker list
    workers:
    - Bill
    - Tom
    - Jane
    ---
    # Performance
    performance:
    -
    project:
    company: Foomatic.com
    name: Fooz 2.0
    worker: Jane
    times:
    start: 2013-06-28 13:41:12
    stop: 2013-06-28 17:16:23
    duration: 03:35:11[/code]
    As you can probably imagine, the YAML is a lot easier to deal with than the XML version if something goes wrong later (and something will go wrong), especially since there is no canonical element representation for XML (is value X an attribute, an enclosed data stream, or an attribute value?) and the mapping between your Python data and your working data is direct (its like JSON, but more cowbell).

    That's simple enough, and just from glancing at that its easy to imagine how you might pass over the data to get what you want, generate new dicts that conform to the ones above and append them to the appropriate list here and there, etc.

    But serialized data structures force you into a heirarchy, and your data is inherently relational in nature -- your worker entities are connected to project entities via a natural many-to-many relationship defined by time span. You will need to write a decent amount of code (no matter what style you choose) to guarantee the relationships stay within bounds. The typical reaction on discovery of this is to simply ignore the problem and hope it goes away -- which is really a silent wish that the project never, ever grows beyond its initially conceived size and requirements and that nobody ever discovers a corner case you forgot to write a special routine to handle.

    (Speaking of bounds, we still don't know when each project itself starts and stops, so we can't yet determine possible/impossible work relationships. Easy to add a time span to the project entries, but introduces a lot of extra sanity checking code to make that data useful.)

    You can unload this entire burden on a database and never have to think about it past defining your data (with thought). I suspect that even using sqlite within Python would suffice -- which would permit your program to run anywhere without the need to contact a db server or have one installed locally...

    Anyway, you'll find that almost anything to do with time tracking and calendaring is actually quite a bear to make work right in every situation. My original advice stands: avoid objects as much as possible in the core logic, don't worry about user options or GUI stuff or whatever just yet, and focus on your core functionality using just console input and output for right now.
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    12
    Rep Power
    0
    Wow...that's a lot to take in...

    I appreciate you taking the time to write all of that and help me understand why database is better than xml.

    I don't know that much about database other than what I took in my BCIS class recently.

    I had no idea that it would be easier than xml because I thought in order to use a database I had to have a DBMS installed and I was worried that it would be of no use to my company because this company is pretty small and we don't even use DBMS here for some reason (though I suspect it would make things easier on a lot of people here).

    When I thought of xml, I thought hey, its just a simple file with a table in it. I see now this was a mistake to think that.

    You seem to feel like I am getting way ahead of myself because I am talking about the GUI and such. Believe me, I'm not. The only reason I even mentioned the GUI is because I wanted to give everyone an idea of what I want the end result to be. I haven't even started thinking about the GUI and I won't until I have the program working first.

    I am just working on single snippets of code that eventually will become part of a module and then part of the program.

    Don't worry about whether I am getting ahead of myself.

    And even if I do eventually get ahead of myself somehow, its a learning experience!

    Thanks!
    Zach
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Location
    Usually Japan when not on contract
    Posts
    240
    Rep Power
    12
    As for databases... in this particular use case it just so happens that Postgres 9.2 (released last year) has a new feature that makes time handing (sorting, avoiding collisions, indexing over spans, etc.) really easy -- which actually solves most of your problem. (Here is a link to the range datatype documentation.)

    But if you're in a situation where you can't put an instance of Postgres on the company lan, then populating sqlite tables inside your Python program from local YAML files would suffice.

    If its a small company, though, and they have a network and your program will be handling less than a million entries at once... you can get away with a Postgres install on a Linux running on an old netbook processor, or on someone's workstation, or whatever for this particular app. In a db like Postgres most of this kind of app will already be finished once you write a solid data schema (the schema will embody the shape and rules of the data, so you don't have to write code for this).

    The only things left to do after that are write a function that gets a connection to the db server from your program (about three lines of code, or more if you have some uber authentication system in the office you need to tie the db into), and write a GUI that understands how to update the db tables, display the relevant data, and look pretty enough to not get you fired (caveat programmer).

    This is a pretty down-to-the-facts type of app, so its just data in, rule checks, and data out that you want. Its nearly always easier to just write everything but the interface in to the db in cases like this (and Postgres is free, by the way).
  16. #9
  17. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    12
    Rep Power
    0
    I'm getting more confused here.

    I don't have any idea what to do now and I don't really understand most of what you are trying to say.

    At this point you're probably thinking, "Holy crap! What an idiot!"

    This is my very first program that I have ever written and I don't know about anything other than basic programming with python.

    After what you have told me, I honestly have no clue where to start now.

    I very much appreciate all of your advice and I really hope you don't think that I am wasting your time. I am trying very hard to understand what you are talking about.

    My company consists of a few designers, myself, some workers in the warehouse... This isn't something I am doing for work, its something I am doing for fun and to learn more about programming. I just thought it would be helpful to us here because currently we use a spreadsheet to keep track of what projects we work on and how much time we spend on them. Its a hassle.

    I tried looking up YAML and I can't figure out what it is or how to use it. Maybe I'm just looking in the wrong place.

    I don't know what else to tell you. Maybe this is too complex of a program for me right now but I didn't know where else to start. All I wanted to do was write a simple program that would force me to learn and that would give me a little experience in coding.

    Zach
  18. #10
  19. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Location
    Usually Japan when not on contract
    Posts
    240
    Rep Power
    12
    Originally Posted by zkirkland
    I don't know what else to tell you. Maybe this is too complex of a program for me right now but I didn't know where else to start. All I wanted to do was write a simple program that would force me to learn and that would give me a little experience in coding.
    When in doubt, do something. It'll be way wrong, but that's OK, fixing it is where you will learn. Almost nobody sits down and writes even a trivial program in one go.

    So just try something simple, like write a program that can accept input of company names from a command line, and save that as a list in a file somewhere. Just that. If you can do that, then you can write this program, because its a small step from there to keeping lists of projects and workers, and a small skip to keeping a few lists of how those things relate to one another.

    You just have to accept that timekeeping is actually not a very straightforward subject, so you will have a bit to learn along the way (which is the whole point, right?). You can leave timekeeping for the very last part, after you feel comfortable with file I/O and after you've learned how to make use of db-type things from within Python.

    Keep in mind that in programming (as in most things) if you understand what you are doing then you're not learning anything. Never be afraid to rewrite something that you don't feel right about or that doesn't work quite the way you'd like it to. The flip side of that attitude is that you shouldn't be afraid of writing something you know will not work the way you intend the first time through. Whatever you do you need a platform for change before you can start changing stuff around, right? It almost doesn't matter what it is -- which is why I recommend the simple listkeeper for now.
    Last edited by zxq9; July 1st, 2013 at 11:17 AM.
  20. #11
  21. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    12
    Rep Power
    0
    Sounds good! Thanks for your help!

    So far I have a small command line that accepts the commands "start", "stop", "elapsed", and "end". These will print out the current time, the elapsed time, and "end" will end the program. Anything other than that outputs "unknown command".

    And I am working on a separate file that handles the inputs of "company name", "project", "project description".

    After that I will start trying to do the db...I think...I'm still not sure at all where to even start with the db...lol.

    Zach
  22. #12
  23. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Location
    Usually Japan when not on contract
    Posts
    240
    Rep Power
    12
    Originally Posted by zkirkland
    After that I will start trying to do the db...I think...I'm still not sure at all where to even start with the db...lol.
    You're headed in the right direction. Don't worry about the db just yet. Don't even worry about saving files.

    Try modifying your program so that you can input something, then have it displayed back only if you ask, and then add more data to it if you want or quit. Ideally this would have a mini menu (old-school door game style -- don't worry about using a cool interface library or anything yet).

    See if you can get something like the following to happen:
    Code:
    Do what?
    [L]ist companies
    [I]nput company names
    [Q]uit
    -> L
    Companies:
    - None
    Do what?
    [L]ist companies
    [I]nput company names
    [Q]uit
    -> I
    Type Name -> Bob's Burgers
    Do what?
    [L]ist companies
    [I]nput company names
    [Q]uit
    -> L
    Companies:
    - Bob's Burgers
    Do what?
    [L]ist companies
    [I]nput company names
    [Q]uit
    -> I
    Type Name -> Bad Furniture, Inc.
    Do what?
    [L]ist companies
    [I]nput company names
    [Q]uit
    -> L
    Companies:
    - Bob's Burgers
    - Bad Furniture, Inc.
    Do what?
    [L]ist companies
    [I]nput company names
    [Q]uit
    -> Q
    If you can accomplish this, then you are ready to move on to saving information in a file. (And its a very short step from there to db interaction, so you're already surprisingly close if you can accomplish the task above.)
  24. #13
  25. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    12
    Rep Power
    0
    Ok... I got that part down... for the most part. I have a simple command line interface that when the appropriate command is entered, it will ask the user for data and stores that data as the company, project, and description in separate lists.

    Then when you print it, it prints out those three lists.

    (having trouble getting it to print in a nice looking way but that's not really important)

    I have a module that gets start time, end time, and then calculates the difference between the two using the datetime function.

    I don't know yet if it will work if the person works past midnight.

    I haven't yet figured out how to check this using specific dates.

    Zach
  26. #14
  27. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Location
    Usually Japan when not on contract
    Posts
    240
    Rep Power
    12
    Originally Posted by zkirkland
    I have a module that gets start time, end time, and then calculates the difference between the two using the datetime function.

    I don't know yet if it will work if the person works past midnight
    You're on the right track. Try having the start/end times be datetime objects instead of just times. That way running past midnight isn't a big deal -- you can diff any two timestamps and find out the duration -- which is what you're really after. Once you get that to work, see if you can turn the list of companies into a list of dictionaries similar to:
    python Code:
    [{'name': 'Big Company, Inc.',
      'time worked': [(start, end), (start, end)]},
     {'name': 'Another Company, LTD',
      'time worked': [(start, end), (start, end), (start, end)]}]

    and make it so that you can pick a company, enter a new time span, and then ask to see total time worked per company if requested.

    Once that works we'll move some things around, but by then you'll be very close to a very early alpha text version of your program. The only thing that's missing is the workers who worked the times.

IMN logo majestic logo threadwatch logo seochat tools logo