From 43f13205bfc54af2abccc2598c06f4e89849171b Mon Sep 17 00:00:00 2001 From: Blake Ridgway Date: Wed, 19 Mar 2025 07:08:52 -0500 Subject: [PATCH] first commit --- README.md | 69 ++++++++++++++++++++++++++++ time_logix.py | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 README.md create mode 100644 time_logix.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..1bc0424 --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# TimeLogix + +TimeLogix is a simple, intuitive Tkinter-based time tracking application designed to help contractors log and manage their working hours effectively. This tool was created so I could keep proper track of time worked under a contract for a company, ensuring accurate record-keeping and easy export of session data for billing and reporting purposes. + +## Features + +- **Start/Stop Tracking:** Easily log your work sessions with start and stop buttons. +- **Session Logging:** View session start times, end times, and durations both in \(H:MM:SS\) and decimal hours. +- **CSV Export:** Export your session data to a CSV file for further processing or billing. +- **Simple UI:** A clean and minimal user interface built using Tkinter. + +## Requirements + +- Python 3.x +- Tkinter (usually included with standard Python installations) + +## Installation + +1. **Clone the Repository:** + + ```bash + git clone https://github.com/yourusername/timelogix.git + cd timelogix + ``` + +2. **(Optional) Create and Activate a Virtual Environment:** + + ```bash + python -m venv venv + source venv/bin/activate # On Windows use `venv\Scripts\activate` + ``` + +3. **Install Dependencies:** + + There are no additional dependencies beyond the Python Standard Library. However, ensure you have the latest version of Python installed. + +## Usage + +Run the application using Python: + +```bash +python time_logix.py +``` + +### How to Use + +1. **Start Tracking:** + - Click the **Start Tracking** button to log the starting time of your work session. +2. **Stop Tracking:** + - Click the **Stop Tracking** button to end the session. The app will display and log the duration in both formats, e.g., `1:30:00` and `1.50 hours`. +3. **Export Sessions:** + - Once you’re finished working, click the **Export Sessions** button to save your session data into `working_sessions.csv`. + +## Customizations + +- **Decimal Hours:** The app calculates hours worked in decimal format using a helper function. +- **CSV File Export:** Sessions are exported to a CSV file with headers: `Start Time`, `End Time`, `Duration (H:MM:SS)`, and `Decimal Hours`. + +## Contributing + +Contributions are welcome! Feel free to fork the repository, make changes, and submit pull requests. For any major changes, please open an issue first to discuss what you would like to change. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## Contact + +For any questions or suggestions, please contact [blake@blakeridgway.com](mailto:blake@blakeridgway.com). diff --git a/time_logix.py b/time_logix.py new file mode 100644 index 0000000..0afb655 --- /dev/null +++ b/time_logix.py @@ -0,0 +1,123 @@ +import tkinter as tk +from tkinter import messagebox +from datetime import datetime +import csv +import os + +class TimeLogix(tk.Tk): + def __init__(self): + super().__init__() + self.title("Time Logix") + self.geometry("450x350") + + self.start_time = None + self.tracking = False + self.sessions = [] + + self.create_widgets() + + def create_widgets(self): + self.status_label = tk.Label(self, text="Status: Not Tracking", font=("Helvetica", 12)) + self.status_label.pack(pady=10) + + self.start_button = tk.Button( + self, text="Start Tracking", width=20, command=self.start_tracking + ) + self.start_button.pack(pady=5) + + self.stop_button = tk.Button( + self, text="Stop Tracking", width=20, command=self.stop_tracking, state=tk.DISABLED + ) + self.stop_button.pack(pady=5) + + self.export_button = tk.Button( + self, text="Export Sessions", width=20, command=self.export_sessions + ) + self.export_button.pack(pady=5) + + self.log_text = tk.Text(self, height=10, state=tk.DISABLED) + self.log_text.pack(pady=10, padx=10, fill='both', expand=True) + + def log_message(self, message): + """Append message to the log text widget.""" + self.log_text.configure(state=tk.NORMAL) + self.log_text.insert(tk.END, f"{message}\n") + self.log_text.configure(state=tk.DISABLED) + self.log_text.see(tk.END) + + def start_tracking(self): + if self.tracking: + messagebox.showwarning("Warning", "Already tracking!") + return + + self.start_time = datetime.now() + self.tracking = True + self.status_label.config( + text=f"Status: Tracking started at {self.start_time.strftime('%H:%M:%S')}" + ) + self.log_message(f"Started at: {self.start_time.strftime('%Y-%m-%d %H:%M:%S')}") + self.start_button.config(state=tk.DISABLED) + self.stop_button.config(state=tk.NORMAL) + + def stop_tracking(self): + if not self.tracking: + messagebox.showwarning("Warning", "Not currently tracking!") + return + + end_time = datetime.now() + duration = end_time - self.start_time + self.sessions.append((self.start_time, end_time, duration)) + self.tracking = False + self.status_label.config(text="Status: Not Tracking") + decimal_hours = self.get_decimal_hours(duration) + self.log_message( + f"Stopped at: {end_time.strftime('%Y-%m-%d %H:%M:%S')}, Duration: {self.format_duration(duration)} " + f"({decimal_hours:.2f} hours)" + ) + self.start_button.config(state=tk.NORMAL) + self.stop_button.config(state=tk.DISABLED) + + def format_duration(self, duration): + """Format duration as H:MM:SS""" + total_seconds = int(duration.total_seconds()) + hours = total_seconds // 3600 + minutes = (total_seconds % 3600) // 60 + seconds = total_seconds % 60 + return f"{hours}:{minutes:02d}:{seconds:02d}" + + def get_decimal_hours(self, duration): + """Convert a timedelta duration to decimal hours.""" + total_hours = duration.total_seconds() / 3600 + return total_hours + + def export_sessions(self): + if not self.sessions: + messagebox.showinfo("Info", "No sessions to export.") + return + + filename = "working_sessions.csv" + try: + file_exists = os.path.isfile(filename) + with open(filename, mode="a", newline="") as csvfile: + writer = csv.writer(csvfile) + if not file_exists: + writer.writerow([ + "Start Time", "End Time", + "Duration (H:MM:SS)", "Decimal Hours" + ]) + for session in self.sessions: + start, end, duration = session + writer.writerow([ + start.strftime("%Y-%m-%d %H:%M:%S"), + end.strftime("%Y-%m-%d %H:%M:%S"), + self.format_duration(duration), + f"{self.get_decimal_hours(duration):.2f}" + ]) + messagebox.showinfo("Export Successful", f"Sessions exported to {filename}") + self.sessions.clear() + except Exception as e: + messagebox.showerror("Error", f"Failed to export: {e}") + +if __name__ == "__main__": + app = TimeLogix() + app.mainloop()