9.6 KiB
Timezone Handling Refactoring Plan
Current Issues
The baby tracker application currently has several issues with timezone handling:
-
Redundant Functionality:
app/context/timezone.tsxprovides client-side timezone utilitiesapp/api/timezone/route.tsoffers API endpoints for timezone operationsapp/api/utils/timezone.tscontains server-side timezone utilities- Components like
activity-tile-utils.tsimplement their own time formatting
-
Inconsistent Usage:
- Some components use the timezone context directly
- Others pass timezone as props
- Some implement their own formatting logic
- This creates inconsistency in how times are displayed
-
Inconsistent Date Storage:
- In
feed-log/route.ts, dates are stored as local time withconst localTime = new Date(body.time) - Similarly in
sleep-log/route.ts, dates are stored as local time withconst startTime = new Date(body.startTime) - This is problematic because it doesn't properly account for timezone differences
- In
-
Incorrect Date Serialization:
- APIs use
toLocaleString()when returning dates in responses - This converts dates to strings using the server's locale, not the client's
- This creates inconsistency when clients are in different timezones
- APIs use
-
Manual Duration Calculations:
- Sleep duration is calculated with
Math.round((endTime.getTime() - startTime.getTime()) / 60000) - This doesn't account for DST changes that might occur between start and end times
- Sleep duration is calculated with
Proposed Solution
We will implement a standardized approach to timezone handling with a clear separation of concerns:
-
Single Source of Truth:
- One timezone context provider that handles all client-side timezone needs
- One server-side utility for API operations
-
Clear Separation of Concerns:
- Server: Always store dates in UTC
- Client: Convert to local timezone for display
-
Simplified API:
- Provide a small set of well-named utility functions that handle common operations
- Make these functions available through the context
Implementation Checklist
Phase 1: Server-Side Standardization
-
1.1 Update Server-Side Timezone Utilities
- Refactor
app/api/utils/timezone.tsto focus on core UTC conversion functions - Add comprehensive JSDoc comments for all functions
- Implement proper error handling for all functions
- Add unit tests for timezone utilities
- Refactor
-
1.2 Standardize API Date Handling
- Update
feed-log/route.tsto store dates in UTC - Update
sleep-log/route.tsto store dates in UTC - Update all other API routes that handle dates:
diaper-log/route.tsnote/route.tsbath-log/route.tspump-log/route.tstimeline/route.tsbaby/route.ts
- Standardize response format to use ISO strings for dates
- Update
-
1.3 Simplify API Endpoints
- Remove
app/api/timezone/route.tsas it is replaced by the server-side utilities
- Remove
Phase 2: Client-Side Enhancement
-
2.1 Enhance Timezone Context
- Update
app/context/timezone.tsxwith comprehensive formatting functions - Implement proper DST handling
- Add functions for common operations (format date, calculate duration, etc.)
- Add unit tests for timezone context
- Update
-
2.2 Update Component Utilities
- Refactor
src/components/ui/activity-tile/activity-tile-utils.tsto use timezone context - Remove redundant timezone handling in components
- Ensure consistent time display across the app
- Refactor
Phase 3: Component Updates
-
3.1 Update UI Components
- Update
src/components/ui/status-bubble/index.tsxto use timezone context - Update
src/components/ActivityTileGroup/index.tsxto use timezone context - Update
src/components/ui/activity-tile/index.tsxto use timezone context - Update
src/components/ui/activity-tile/activity-tile-content.tsxto use timezone context - Update
src/components/debugTimezone/index.tsxto:- Fetch server timezone from settings API
- Only show in development mode
- Update
-
3.2 Update Form Components
- Update
src/components/forms/FeedForm/index.tsxto use timezone context - Update
src/components/forms/SleepForm/index.tsxto use timezone context - Update
src/components/forms/DiaperForm/index.tsxto use timezone context - Update
src/components/forms/BathForm/index.tsxto use timezone context - Update
src/components/forms/NoteForm/index.tsxto use timezone context - Update
src/components/forms/PumpForm/index.tsxto use timezone context
- Update
Phase 4: Testing and Documentation
-
4.1 Documentation
- Update
app/api/utils/timezone.README.mdwith new architecture - Update
app/context/timezone.README.mdwith usage examples - Add inline documentation for all timezone-related functions
- Update
-
4.2 Testing
- Test timezone handling with users in different timezones
- Test DST edge cases
- Test date calculations across timezone boundaries
Phase 5: Migration and Cleanup
-
5.1 Data Migration
- Create a migration script to convert existing dates to UTC
- Test migration script with sample data
- Run migration script on production data
-
5.2 Cleanup
- Remove
app/api/timezone/route.tsif no longer needed - Remove redundant timezone functions from components
- Remove any unused imports or variables
- Remove
Current Status (March 20, 2025)
Completed
-
Server-Side Standardization
- ✅ Refactored
app/api/utils/timezone.tswith new core functions:toUTC: Converts dates to UTC for storageformatForResponse: Formats dates as ISO strings for responsescalculateDurationMinutes: Calculates duration between datesformatDuration: Formats duration in minutes to HH:MM format
- ✅ Updated all API routes to store dates in UTC and use ISO strings for responses:
feed-log/route.tssleep-log/route.tsdiaper-log/route.tsnote/route.tsbath-log/route.tspump-log/route.tstimeline/route.tsbaby/route.ts
- ✅ Removed redundant
app/api/timezone/route.tsendpoint - ✅ Updated documentation in
app/api/utils/timezone.README.md
- ✅ Refactored
-
Client-Side Enhancement
- ✅ Updated
app/context/timezone.tsxwith comprehensive formatting functions:formatDate: Formats an ISO date string with specified format optionsformatTime: Formats a time-only representationformatDateOnly: Formats a date-only representationformatDateTime: Formats a date and time representationcalculateDurationMinutes: Calculates duration between datesformatDuration: Formats duration in minutes to HH:MM formatisToday: Checks if a date is todayisYesterday: Checks if a date is yesterday
- ✅ Updated documentation in
app/context/timezone.README.md - ✅ Updated
src/components/ui/status-bubble/index.tsxto use the new timezone context - ✅ Updated
src/components/ui/activity-tile/activity-tile-utils.tsto use the new timezone context:- Created a new
useActivityDescriptionhook that uses the timezone context - Maintained backward compatibility with a deprecated warning
- Created a new
- ✅ Updated
src/components/ui/activity-tile/activity-tile-content.tsxto use the new hook - ✅ Updated
src/components/ui/activity-tile/index.tsxto remove the userTimezone prop - ✅ Updated
src/components/debugTimezone/index.tsxto:- Fetch server timezone from settings API
- Only show in development mode (similar to debugSessionTimer)
- ✅ Updated
-
Form Components
- ✅ Updated all form components to use the timezone context:
src/components/forms/DiaperForm/index.tsxsrc/components/forms/BathForm/index.tsxsrc/components/forms/NoteForm/index.tsxsrc/components/forms/PumpForm/index.tsxsrc/components/forms/SleepForm/index.tsxsrc/components/forms/FeedForm/index.tsx
- ✅ Improved form submissions to send ISO strings directly to the API
- ✅ Updated duration calculations to use the timezone context's
calculateDurationMinutesfunction
- ✅ Updated all form components to use the timezone context:
In Progress
- Component Updates
- Next step: Update
src/components/ActivityTileGroup/index.tsxto use timezone context
- Next step: Update
Pending
-
Testing and Validation
- Test timezone handling with users in different timezones
- Test DST edge cases
- Test date calculations across timezone boundaries
-
Data Migration
- Create a migration script to convert existing dates to UTC if needed
- Test and run migration script
Expected Outcomes
After implementing this plan, we expect:
- Consistent Date Storage: All dates will be stored in UTC format in the database
- Standardized API Responses: All API responses will include dates in ISO format
- Simplified Component Code: Components will use the timezone context for all date operations
- Improved User Experience: Times will be correctly displayed in the user's timezone
- Better Maintainability: Timezone logic will be centralized and easier to update
- Proper DST Handling: The application will correctly handle Daylight Saving Time changes
Success Criteria
The refactoring will be considered successful when:
- All dates are stored in UTC in the database
- All components use the timezone context for date formatting
- Users in different timezones see correct times
- DST changes are handled correctly
- No redundant timezone code exists in components
- All tests pass, including timezone-specific tests