mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-24 15:20:52 -05:00
Fix manual time entry timezone (Issue #471)
Manual time entries were interpreted in the application timezone instead of the user's timezone, so users in a different timezone (e.g. GMT+1) saw times adjusted to the server timezone (e.g. GMT+0) on the calendar. - Add parse_user_local_datetime() in timezone utils to parse form date/time as the user's local time and return naive datetime in app timezone for storage. - Use parse_user_local_datetime() in the manual entry form so submitted times are stored correctly and display at the right slot in the calendar. Calendar events and drag-created entries were already correct; only the manual entry form path is changed. Other callers of parse_local_datetime are unchanged.
This commit is contained in:
+4
-4
@@ -3,7 +3,7 @@ from flask_babel import gettext as _
|
||||
from flask_login import login_required, current_user
|
||||
from app import db, socketio, log_event, track_event
|
||||
from app.models import User, Project, TimeEntry, Task, Settings, Activity, Client
|
||||
from app.utils.timezone import parse_local_datetime, utc_to_local
|
||||
from app.utils.timezone import parse_local_datetime, parse_user_local_datetime, utc_to_local
|
||||
from datetime import datetime, timedelta
|
||||
import json
|
||||
from app.utils.db import safe_commit
|
||||
@@ -1068,10 +1068,10 @@ def manual_entry():
|
||||
prefill_end_time=end_time,
|
||||
)
|
||||
|
||||
# Parse datetime with timezone awareness
|
||||
# Parse datetime: treat form input as user's local time, store in app timezone
|
||||
try:
|
||||
start_time_parsed = parse_local_datetime(start_date, start_time)
|
||||
end_time_parsed = parse_local_datetime(end_date, end_time)
|
||||
start_time_parsed = parse_user_local_datetime(start_date, start_time, current_user)
|
||||
end_time_parsed = parse_user_local_datetime(end_date, end_time, current_user)
|
||||
except ValueError:
|
||||
flash(_("Invalid date/time format"), "error")
|
||||
return render_template(
|
||||
|
||||
@@ -222,6 +222,26 @@ def parse_local_datetime(date_str, time_str):
|
||||
raise ValueError(f"Invalid date/time format: {e}")
|
||||
|
||||
|
||||
def parse_user_local_datetime(date_str, time_str, user=None):
|
||||
"""Parse date and time strings as user's local time; return naive datetime in app timezone for storage.
|
||||
|
||||
Use this for manual time entry forms where the user enters a time in their local timezone.
|
||||
When user has no timezone set, falls back to app timezone (same as parse_local_datetime input semantics).
|
||||
"""
|
||||
try:
|
||||
datetime_str = f"{date_str} {time_str}"
|
||||
naive_dt = datetime.strptime(datetime_str, "%Y-%m-%d %H:%M")
|
||||
|
||||
# Treat input as user's timezone (or app timezone if no user / no user TZ)
|
||||
user_tz = get_timezone_for_user(user)
|
||||
app_tz = get_timezone_obj()
|
||||
localized_in_user_tz = _localize_with_timezone(naive_dt, user_tz)
|
||||
in_app_tz = localized_in_user_tz.astimezone(app_tz)
|
||||
return in_app_tz.replace(tzinfo=None)
|
||||
except ValueError as e:
|
||||
raise ValueError(f"Invalid date/time format: {e}")
|
||||
|
||||
|
||||
def format_local_datetime(utc_dt, format_str="%Y-%m-%d %H:%M"):
|
||||
"""Format UTC datetime in local application timezone."""
|
||||
if utc_dt is None:
|
||||
|
||||
Reference in New Issue
Block a user