@@ -201,14 +204,15 @@ function Summary({ startDate, endDate }) {
{topContactsData.length > 0 ? (
-
+
truncate(val, 22)}
/>
[value.toLocaleString(), 'Messages']}
diff --git a/internal/database.go b/internal/database.go
index 251b908..567cc8b 100644
--- a/internal/database.go
+++ b/internal/database.go
@@ -1046,7 +1046,7 @@ func SearchMessages(userDB *sql.DB, query string, limit int) ([]SearchResult, er
}
// GetAnalytics retrieves analytics data for the Summary tab
-func GetAnalytics(userDB *sql.DB, startDate, endDate *time.Time, topN int) (*AnalyticsResponse, error) {
+func GetAnalytics(userDB *sql.DB, startDate, endDate *time.Time, topN int, tzOffsetMinutes int) (*AnalyticsResponse, error) {
analytics := &AnalyticsResponse{}
// Build date filter
@@ -1074,7 +1074,7 @@ func GetAnalytics(userDB *sql.DB, startDate, endDate *time.Time, topN int) (*Ana
analytics.TopContacts = topContacts
// 3. Get hourly distribution
- hourly, err := getHourlyDistribution(userDB, dateFilter, args)
+ hourly, err := getHourlyDistribution(userDB, dateFilter, args, tzOffsetMinutes)
if err != nil {
return nil, err
}
@@ -1154,10 +1154,11 @@ func getTopContacts(userDB *sql.DB, dateFilter string, args []interface{}, limit
return contacts, nil
}
-func getHourlyDistribution(userDB *sql.DB, dateFilter string, args []interface{}) ([]HourlyDistribution, error) {
+func getHourlyDistribution(userDB *sql.DB, dateFilter string, args []interface{}, tzOffsetMinutes int) ([]HourlyDistribution, error) {
+ tzModifier := fmt.Sprintf("%+d minutes", tzOffsetMinutes)
query := `
SELECT
- CAST(strftime('%H', date, 'unixepoch', 'localtime') AS INTEGER) as hour,
+ CAST(strftime('%H', date, 'unixepoch', '` + tzModifier + `') AS INTEGER) as hour,
COUNT(*) as count
FROM messages
WHERE record_type IN (1, 2) ` + dateFilter + `
diff --git a/internal/handlers.go b/internal/handlers.go
index d7d89e8..8b39cad 100644
--- a/internal/handlers.go
+++ b/internal/handlers.go
@@ -586,7 +586,15 @@ func HandleAnalytics(c echo.Context) error {
}
}
- analytics, err := GetAnalytics(userDB, startDate, endDate, topN)
+ // Timezone offset in minutes from UTC (e.g. -300 for UTC-5, 330 for UTC+5:30)
+ tzOffsetMinutes := 0
+ if tzStr := c.QueryParam("tz_offset"); tzStr != "" {
+ if val, err := strconv.Atoi(tzStr); err == nil && val >= -840 && val <= 840 {
+ tzOffsetMinutes = val
+ }
+ }
+
+ analytics, err := GetAnalytics(userDB, startDate, endDate, topN, tzOffsetMinutes)
if err != nil {
slog.Error("Error getting analytics", "error", err)
return c.JSON(http.StatusInternalServerError, map[string]string{