Website : rimsha.abasa.com
backdoor
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
var
/
www
/
mudeerapi.abasa.com
/
nodetest
/
Filename :
UTC_TIMEZONE_ISSUES.md
back
Copy
# UTC & Timezone Issues Analysis - Mudeer Backend ## ๐ด **CRITICAL ISSUES** ### 1. **Attendance Check - Today's Record Query** **Location**: `src/controllers/attendance.controller.js` (Line 102, 757-758, 1180-1181, 1264-1265) ```javascript // โ PROBLEM: setHours mutates AND uses LOCAL timezone const today = new Date(); const existingAttendance = await attendance.findOne({ user_id: userId, createdAt: { $gte: today.setHours(0, 0, 0, 0) }, }); ``` **Issue**: - `setHours()` uses **local server timezone** (not UTC) - If server is in UTC but users are in GMT+3 (Dubai/Saudi), queries will be off by 3 hours - User marking attendance at 11 PM Dubai time (8 PM UTC) will be considered "tomorrow" by server - `setHours()` also **mutates** the original date object **Impact**: - โ Users can mark attendance multiple times per day - โ Duplicate records in different "days" based on timezone mismatch - โ Cron job marks wrong "today" **Fix**: ```javascript // โ SOLUTION: Use UTC explicitly const todayStart = new Date(); todayStart.setUTCHours(0, 0, 0, 0); const todayEnd = new Date(); todayEnd.setUTCHours(23, 59, 59, 999); const existingAttendance = await attendance.findOne({ user_id: userId, createdAt: { $gte: todayStart, $lte: todayEnd }, }); ``` --- ### 2. **Checkout Query - Hardcoded 6 AM Start** **Location**: `src/controllers/attendance.controller.js` (Line 757-758, 1180, 1264) ```javascript // โ PROBLEM: Hardcoded 6 AM in LOCAL timezone const today = new Date(); const startOfDay = new Date(today.setHours(6, 0, 0, 0)); const endOfDay = new Date(today.setHours(23, 59, 59, 999)); ``` **Issue**: - Assumes work day starts at 6 AM **local server time** - If server is UTC and users are GMT+3, 6 AM UTC = 9 AM user time - Users checking in at 7-8 AM Dubai time won't find their attendance - Inconsistent with midnight-based "today" check in `markAttendance` **Impact**: - โ Checkout fails with "No attendance record found" - โ Break start/stop fails - โ Users forced to re-mark attendance **Fix**: ```javascript // โ Use consistent UTC day boundaries const todayStart = new Date(); todayStart.setUTCHours(0, 0, 0, 0); const todayEnd = new Date(); todayEnd.setUTCHours(23, 59, 59, 999); ``` --- ### 3. **Cron Job - Local Timezone Day Calculation** **Location**: `src/controllers/attendance.controller.js` (Line 858-860) ```javascript // โ PROBLEM: Gets day name in LOCAL timezone const now = new Date(); const today = new Date(now); today.setHours(0, 0, 0, 0); // Local timezone midnight const currentDayName = now.toLocaleDateString("en-US", options); // "Monday" ``` **Issue**: - Cron runs at 23:00 UTC (11 PM UTC) - If users are GMT+3, that's 2 AM next day for them - Day name will be **tomorrow** for users, not "today" - "Weekly off" marked on wrong day **Impact**: - โ Sunday weekly off marked on Monday UTC - โ Users marked absent on wrong day - โ Emails sent with incorrect day reference **Fix**: ```javascript // โ Use UTC or specific timezone const now = new Date(); const todayUTC = new Date(now); todayUTC.setUTCHours(0, 0, 0, 0); // OR: Convert to user timezone (e.g., GMT+3) const userTimezoneOffset = 3 * 60 * 60 * 1000; // 3 hours in ms const userTime = new Date(now.getTime() + userTimezoneOffset); const currentDayName = userTime.toLocaleDateString("en-US", { weekday: "long" }); ``` --- ### 4. **User Status Updater - Local Midnight** **Location**: `src/services/statusUpdater.js` (Line 15-17) ```javascript // โ PROBLEM: Uses local timezone for "today" const now = new Date(); const today = new Date(now); today.setHours(0, 0, 0, 0); // Local timezone ``` **Issue**: - Same as cron job - uses server's local timezone - Queries for "today's" activity might miss records if timezone differs **Impact**: - โ User status (active/inactive) calculated on wrong day - โ Inactivity detection off by timezone offset --- ### 5. **User List - Today's Attendance Lookup** **Location**: `src/controllers/user.controller.js` (Line 280-281, 393-394, 463) ```javascript // โ PROBLEM: Local timezone boundaries const todayStart = new Date(new Date().setHours(0, 0, 0, 0)); const todayEnd = new Date(new Date().setHours(23, 59, 59, 999)); ``` **Issue**: - Dashboard shows "today's" attendance based on server timezone - If admin is in GMT+3 but server is UTC, they see yesterday's data at 2 AM **Impact**: - โ Dashboard shows wrong attendance status - โ "Check In Time" displayed is from wrong day - โ Reports are off by one day --- ## ๐ **HIGH PRIORITY ISSUES** ### 6. **Moment.js Date Range Queries** **Location**: `src/controllers/attendance.controller.js` (Line 664-707) ```javascript // โ ๏ธ ISSUE: Moment uses LOCAL timezone by default const startDate = moment(req.query.date, "YYYY-MM-DD").startOf("day"); const endDate = moment(req.query.date, "YYYY-MM-DD").endOf("day"); queryConditions.createdAt = { $gte: startDate.toDate(), $lte: endDate.toDate(), }; ``` **Issue**: - `moment()` without `.utc()` uses **local server timezone** - `.startOf('day')` = 00:00:00 **local time** - If user requests "2024-01-15" from Dubai (GMT+3), but server is UTC: - User expects: 2024-01-15 00:00:00 GMT+3 to 23:59:59 GMT+3 - Server queries: 2024-01-15 00:00:00 UTC to 23:59:59 UTC - **Result**: Missing 3 hours of data at start, including 3 extra hours at end **Impact**: - โ Date filter returns wrong records - โ Monthly/yearly reports show incorrect data - โ Week boundaries don't align with user's week **Fix**: ```javascript // โ SOLUTION: Use UTC explicitly const startDate = moment.utc(req.query.date, "YYYY-MM-DD").startOf("day"); const endDate = moment.utc(req.query.date, "YYYY-MM-DD").endOf("day"); // OR: Accept timezone from client and convert const startDate = moment.tz(req.query.date, "YYYY-MM-DD", "Asia/Dubai").startOf("day").utc(); ``` --- ### 7. **Event Activity & Active Window Queries** **Location**: - `src/controllers/eventActivity.controller.js` (Line 102-122) - `src/controllers/activeWindow.controller.js` (Line 108-120) ```javascript // โ ๏ธ Same moment.js local timezone issue startDate = moment(req.query.month).startOf('month'); endDate = moment(req.query.month).endOf('month'); ``` **Issue**: Same as #6 - all date range queries affected --- ### 8. **Leave Year Calculation** **Location**: `src/controllers/leave.controller.js` (Line 85-86) ```javascript // โ ๏ธ ISSUE: Year boundaries in LOCAL timezone const startOfYear = new Date(currentYear, 0, 1); const endOfYear = new Date(currentYear + 1, 0, 0, 23, 59, 59, 999); ``` **Issue**: - `new Date(2024, 0, 1)` = January 1, 2024 00:00:00 **local time** - Leave year boundaries don't align with calendar year in user's timezone **Impact**: - โ Leave balance migration counts wrong year - โ First/last day of year might be missed or double-counted --- ## ๐ก **MEDIUM PRIORITY ISSUES** ### 9. **Time Comparison - Late vs Present** **Location**: `src/controllers/attendance.controller.js` (Line 96, 149) ```javascript // โ ๏ธ ISSUE: Comparing dates without timezone context function convertTo24HourFormat(time) { // ... return new Date(0, 0, 0, hours, minutes); // No timezone specified } const currentTime = new Date(); // Server local time if (currentTime > startTime) { // Comparing different timezone contexts if (timeDifferenceInSeconds > 600) { AttendanceStatus = "Late"; } } ``` **Issue**: - User's `start_time` is stored as string "9:00 AM" without timezone - Server converts to `Date` object in **local timezone** - Comparison assumes both are in same timezone **Impact**: - โ ๏ธ Wrong "Late" marking if server and user in different timezones - โ ๏ธ 10-minute grace period calculated incorrectly --- ### 10. **Date Grouping in Response** **Location**: `src/controllers/eventActivity.controller.js`, `activeWindow.controller.js` ```javascript // โ ๏ธ ISSUE: Grouping by LOCAL timezone dates const date = eventMoment.format('YYYY-MM-DD'); // Uses moment's timezone const dayOfWeek = eventMoment.format('dddd'); ``` **Issue**: - When grouping by day, uses server's interpretation of "day" - A record at 1 AM UTC is "Monday" for server, but "Sunday 10 PM" for GMT-3 user **Impact**: - โ ๏ธ UI shows data grouped by wrong days - โ ๏ธ "Hours passed" totals calculated for wrong days --- ## ๐ข **LOW PRIORITY (Cosmetic/Display)** ### 11. **Notification Timestamps** **Location**: `src/template/notificationTemplates.js` (Line 16, 32, 47, etc.) ```javascript // โน๏ธ INFO: Timestamps in ISO format (UTC) timestamp: new Date().toISOString() ``` **Status**: **โ Actually correct** - ISO format includes UTC offset - Frontend should convert to user's local time for display --- ### 12. **Login/Checkout Time Display** **Location**: `src/services/notificationService.js` (Line 275, 350) ```javascript // โ ๏ธ ISSUE: toLocaleString() without timezone const loginTime = new Date().toLocaleString(); // Uses server locale ``` **Issue**: - Shows time in server's locale format - User might see "1/15/2024, 3:30:00 PM" when they logged in at 6:30 PM their time **Impact**: - โ ๏ธ Confusing time display in notifications/emails --- ## ๐ **Root Cause Analysis** | Issue Type | Root Cause | Affected Areas | |------------|------------|----------------| | **Date boundaries** | Using `setHours()` instead of `setUTCHours()` | Attendance check, Checkout, Break, Cron | | **Moment.js defaults** | Not using `.utc()` or `.tz()` | All date range queries | | **Cron timing** | Running at UTC 23:00 but checking LOCAL day | Absent marking, Weekly off | | **Hardcoded hours** | 6 AM start hardcoded in local time | Checkout queries | | **No timezone metadata** | User times stored as strings without TZ | Late detection | --- ## ๐ ๏ธ **Recommended Solutions** ### **Option A: Force UTC Everywhere (Simplest)** ```javascript // 1. All database queries use UTC const todayStart = new Date(); todayStart.setUTCHours(0, 0, 0, 0); // 2. All moment queries use UTC const startDate = moment.utc(req.query.date).startOf("day"); // 3. Cron job uses UTC day const currentDayUTC = now.getUTCDay(); // 0-6, where 0 = Sunday // 4. Frontend converts to user timezone for display ``` **Pros**: - Consistent, simple - Database stores true UTC - Works regardless of server location **Cons**: - Cron job runs at "wrong" time for users (11 PM UTC = 2 AM Dubai) - Need timezone awareness in frontend --- ### **Option B: Support User Timezones (Proper Solution)** ```javascript // 1. Add timezone to user model const userSchema = new Schema({ timezone: { type: String, default: 'Asia/Dubai' } // or 'Asia/Riyadh' }); // 2. Accept timezone in requests or read from user profile const userTimezone = req.user.timezone || 'UTC'; // 3. Convert queries to user's timezone const startDate = moment.tz(req.query.date, "YYYY-MM-DD", userTimezone) .startOf("day") .utc(); // Convert back to UTC for DB query // 4. Cron job runs based on user timezone cron.schedule("0 23 * * *", async () => { // For each user, check if it's 11 PM in THEIR timezone for (const user of users) { const userTime = moment().tz(user.timezone); if (userTime.hour() === 23) { // Mark absent for this user } } }); ``` **Pros**: - Accurate for all users - Proper multi-timezone support - Cron jobs run at correct time per user **Cons**: - More complex - Requires migration to add timezone field --- ## ๐ฏ **Priority Fix Order** 1. **๐ด CRITICAL - Fix TODAY** (User-facing bugs): - [ ] Fix attendance duplicate check (Line 102) - use `setUTCHours` - [ ] Fix checkout query (Line 757-758) - remove hardcoded 6 AM - [ ] Fix break queries (Line 1180, 1264) 2. **๐ HIGH - Fix THIS WEEK** (Data accuracy): - [ ] Fix all moment.js queries - add `.utc()` - [ ] Fix cron job day calculation - [ ] Fix user list "today" queries 3. **๐ก MEDIUM - Fix NEXT SPRINT** (Better UX): - [ ] Add timezone field to user model - [ ] Fix time comparison for "Late" detection - [ ] Fix date grouping in reports 4. **๐ข LOW - Future Enhancement**: - [ ] Per-user timezone-aware cron - [ ] Localized time display in notifications --- ## ๐งช **Testing Scenarios** ### Test Case 1: Duplicate Attendance ``` 1. Server in UTC, User in GMT+3 2. User marks attendance at 11:50 PM Dubai time (8:50 PM UTC) 3. Wait until 12:05 AM Dubai time (9:05 PM UTC - still same UTC day) 4. User tries to mark attendance again EXPECTED: Should reject (already marked) ACTUAL (Bug): Allows marking again (checks local midnight) ``` ### Test Case 2: Checkout Not Found ``` 1. User marks attendance at 8 AM Dubai time (5 AM UTC) 2. User works until 5 PM Dubai time (2 PM UTC) 3. User clicks checkout EXPECTED: Finds morning attendance and checks out ACTUAL (Bug): "No attendance found" (query starts at 6 AM local = 6 AM UTC) ``` ### Test Case 3: Wrong Day Report ``` 1. User requests attendance for "2024-01-15" from Dubai 2. They worked 8 AM - 5 PM Dubai time (5 AM - 2 PM UTC) EXPECTED: Shows 8 AM - 5 PM record ACTUAL (Bug): Missing first 3 hours (query starts at 00:00 UTC, not GMT+3) ``` --- ## ๐ **Configuration Recommendation** Add to `.env`: ```bash # Timezone configuration TZ=UTC # Force UTC for consistency DEFAULT_USER_TIMEZONE=Asia/Dubai # Default for new users CRON_TIMEZONE=Asia/Dubai # Run crons in user timezone ``` Add to `src/config/timezone.js`: ```javascript export const TIMEZONES = { UAE: 'Asia/Dubai', SAUDI: 'Asia/Riyadh', KUWAIT: 'Asia/Kuwait', UTC: 'UTC' }; export const getUserTimezone = (user) => { return user.timezone || process.env.DEFAULT_USER_TIMEZONE || 'UTC'; }; ``` --- ## ๐ **Additional Notes** - **MongoDB**: Stores dates in UTC by default (ISODate format) - **Moment.js**: Deprecated - consider migrating to `dayjs` or `date-fns` with `date-fns-tz` - **Best Practice**: Store all dates in UTC, convert to user timezone only for display - **Server Location**: If server moves from UTC to another timezone, ALL queries break --- ## โ **Verification Checklist** After fixes: - [ ] Attendance can only be marked once per day (any timezone) - [ ] Checkout works regardless of check-in time - [ ] Date filters return correct records - [ ] Cron jobs mark correct day for users - [ ] Dashboard shows today's data (user's today) - [ ] Reports show data for requested dates (user's dates) - [ ] Late detection works across timezones - [ ] Weekly off detected on correct day