Skip to content

Commit

Permalink
fix timezones
Browse files Browse the repository at this point in the history
  • Loading branch information
Tanishq Rupaal authored and Tanishq Rupaal committed Feb 1, 2025
1 parent 732f330 commit 9e4ef6f
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 46 deletions.
3 changes: 3 additions & 0 deletions internal/api/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ func (h *Handler) AddExpense(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusBadRequest, ErrorResponse{Error: "Invalid request body"})
return
}
if !req.Date.IsZero() {
req.Date = req.Date.UTC()
}
expense := &models.Expense{
Name: req.Name,
Category: req.Category,
Expand Down
57 changes: 38 additions & 19 deletions internal/web/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -253,25 +253,42 @@ <h1 align="center">ExpenseOwl</h1>
Chart.defaults.color = '#b3b3b3';
Chart.defaults.borderColor = '#606060';
Chart.defaults.font.family = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
// Format month for display

// Helpers
function formatMonth(date) {
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long'
month: 'long',
timeZone: getUserTimeZone()
});
}
function getISODateWithLocalTime(dateInput) {
const [year, month, day] = dateInput.split('-').map(Number);
const now = new Date();
const hours = now.getHours();
const minutes = now.getMinutes();
const seconds = now.getSeconds();
const localDateTime = new Date(year, month - 1, day, hours, minutes, seconds);
return localDateTime.toISOString();
}
function getUserTimeZone() {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}

// Update month display and navigation buttons
function updateMonthDisplay() {
document.getElementById('currentMonth').textContent = formatMonth(currentDate);
// Disable next month button if current month is reached
const now = new Date();
const isCurrentMonth = currentDate.getMonth() === now.getMonth() && currentDate.getFullYear() === now.getFullYear();
document.getElementById('nextMonth').disabled = isCurrentMonth;
}
// Get start and end of month
function getMonthBounds(date) {
const start = new Date(date.getFullYear(), date.getMonth(), 1);
const end = new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59);
const localDate = new Date(date);
const startLocal = new Date(localDate.getFullYear(), localDate.getMonth(), 1);
const endLocal = new Date(localDate.getFullYear(), localDate.getMonth() + 1, 0, 23, 59, 59, 999);
const start = new Date(startLocal.toISOString());
const end = new Date(endLocal.toISOString());
return { start, end };
}
// Filter expenses for current month
Expand All @@ -280,7 +297,7 @@ <h1 align="center">ExpenseOwl</h1>
return expenses.filter(exp => {
const expDate = new Date(exp.date);
return expDate >= start && expDate <= end;
});
}).sort((a, b) => new Date(b.date) - new Date(a.date));
}
function showNoDataMessage() {
if (pieChart) {
Expand All @@ -304,32 +321,34 @@ <h1 align="center">ExpenseOwl</h1>

// Event Listeners
document.getElementById('prevMonth').addEventListener('click', () => {
currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1);
currentDate = new Date(
currentDate.getFullYear(),
currentDate.getMonth() - 1,
1,
currentDate.getHours(),
currentDate.getMinutes()
);
updateMonthDisplay();
updateChartAndLegend();
});
document.getElementById('nextMonth').addEventListener('click', () => {
currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1);
currentDate = new Date(
currentDate.getFullYear(),
currentDate.getMonth() + 1,
1,
currentDate.getHours(),
currentDate.getMinutes()
);
updateMonthDisplay();
updateChartAndLegend();
});
document.getElementById('expenseForm').addEventListener('submit', async (e) => {
e.preventDefault();
const selectedDate = new Date(document.getElementById('date').value);
const now = new Date();
const expenseDate = new Date(
selectedDate.getFullYear(),
selectedDate.getMonth(),
selectedDate.getDate(),
now.getHours(),
now.getMinutes(),
now.getSeconds()
);
const formData = {
name: document.getElementById('name').value,
category: document.getElementById('category').value,
amount: parseFloat(document.getElementById('amount').value),
date: expenseDate.toISOString()
date: getISODateWithLocalTime(document.getElementById('date').value)
};
try {
const response = await fetch('/expense', {
Expand Down
74 changes: 47 additions & 27 deletions internal/web/templates/table.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,21 @@ <h3>Delete Expense</h3>
function formatMonth(date) {
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long'
month: 'long',
timeZone: getUserTimeZone()
});
}
function formatDate(dateString) {
return new Date(dateString).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric'
});
function getISODateWithLocalTime(dateInput) {
const [year, month, day] = dateInput.split('-').map(Number);
const now = new Date();
const hours = now.getHours();
const minutes = now.getMinutes();
const seconds = now.getSeconds();
const localDateTime = new Date(year, month - 1, day, hours, minutes, seconds);
return localDateTime.toISOString();
}
function getUserTimeZone() {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}
function formatCurrency(amount) {
return new Intl.NumberFormat('en-US', {
Expand All @@ -98,17 +104,30 @@ <h3>Delete Expense</h3>
minimumFractionDigits: 2
}).format(amount);
}
function formatDateFromUTC(utcDateString) {
const date = new Date(utcDateString);
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
timeZoneName: 'short'
});
}

function updateMonthDisplay() {
document.getElementById('currentMonth').textContent = formatMonth(currentDate);

const now = new Date();
const isCurrentMonth = currentDate.getMonth() === now.getMonth()
&& currentDate.getFullYear() === now.getFullYear();
const isCurrentMonth = currentDate.getMonth() === now.getMonth() && currentDate.getFullYear() === now.getFullYear();
document.getElementById('nextMonth').disabled = isCurrentMonth;
}
function getMonthBounds(date) {
const start = new Date(date.getFullYear(), date.getMonth(), 1);
const end = new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59);
const localDate = new Date(date);
const startLocal = new Date(localDate.getFullYear(), localDate.getMonth(), 1);
const endLocal = new Date(localDate.getFullYear(), localDate.getMonth() + 1, 0, 23, 59, 59, 999);
const start = new Date(startLocal.toISOString());
const end = new Date(endLocal.toISOString());
return { start, end };
}
function getMonthExpenses(expenses) {
Expand Down Expand Up @@ -140,7 +159,7 @@ <h3>Delete Expense</h3>
<td>${expense.name}</td>
<td>${expense.category}</td>
<td class="amount">${formatCurrency(expense.amount)}</td>
<td class="date-column">${formatDate(expense.date)}</td>
<td class="date-column">${formatDateFromUTC(expense.date)}</td>
<td>
<button class="delete-button" onclick="showDeleteModal('${expense.id}')">
<i class="fa-solid fa-trash-can"></i>
Expand Down Expand Up @@ -182,13 +201,24 @@ <h3>Delete Expense</h3>
}

document.getElementById('prevMonth').addEventListener('click', () => {
currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1);
currentDate = new Date(
currentDate.getFullYear(),
currentDate.getMonth() - 1,
1,
currentDate.getHours(),
currentDate.getMinutes()
);
updateMonthDisplay();
updateTable();
});

document.getElementById('nextMonth').addEventListener('click', () => {
currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1);
currentDate = new Date(
currentDate.getFullYear(),
currentDate.getMonth() + 1,
1,
currentDate.getHours(),
currentDate.getMinutes()
);
updateMonthDisplay();
updateTable();
});
Expand Down Expand Up @@ -231,21 +261,11 @@ <h3>Delete Expense</h3>

document.getElementById('expenseForm').addEventListener('submit', async (e) => {
e.preventDefault();
const selectedDate = new Date(document.getElementById('date').value);
const now = new Date();
const expenseDate = new Date(
selectedDate.getFullYear(),
selectedDate.getMonth(),
selectedDate.getDate(),
now.getHours(),
now.getMinutes(),
now.getSeconds()
);
const formData = {
name: document.getElementById('name').value,
category: document.getElementById('category').value,
amount: parseFloat(document.getElementById('amount').value),
date: expenseDate.toISOString()
date: getISODateWithLocalTime(document.getElementById('date').value)
};
try {
const response = await fetch('/expense', {
Expand Down

0 comments on commit 9e4ef6f

Please sign in to comment.