Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions app/src/components/blog/BlogPostCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IconArrowRight } from '@tabler/icons-react';
import { Link } from 'react-router-dom';
import { formatPostDate } from '@/components/home/blogPreviewUtils';
import { Text } from '@/components/ui';
import OptimisedImage from '@/components/ui/OptimisedImage';
import { locationLabels, topicLabels } from '@/data/posts/postTransformers';
Expand All @@ -16,11 +17,7 @@ export function BlogPostCard({ item, countryId }: BlogPostCardProps) {
? `/${item.countryId}/${item.slug}`
: `/${countryId}/research/${item.slug}`;

const formattedDate = new Date(item.date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
});
const formattedDate = formatPostDate(item.date);

const displayTags = item.tags
.filter((tag) => topicLabels[tag] || locationLabels[tag])
Expand Down
4 changes: 2 additions & 2 deletions app/src/components/home/blogPreviewUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ export function getPostImageUrl(post: BlogPost): string {
return `/assets/posts/${post.image}`;
}

export function formatPostDate(dateStr: string): string {
export function formatPostDate(dateStr: string, month: 'short' | 'long' = 'short'): string {
// Append T12:00:00 to date-only strings to avoid UTC midnight timezone shift
const normalized = /^\d{4}-\d{2}-\d{2}$/.test(dateStr) ? `${dateStr}T12:00:00` : dateStr;
return new Date(normalized).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
month,
day: 'numeric',
});
}
7 changes: 2 additions & 5 deletions app/src/pages/Blog.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { blogSpacing } from '@/components/blog/blogStyles';
import { MarkdownFormatter } from '@/components/blog/MarkdownFormatter';
import { NotebookRenderer } from '@/components/blog/NotebookRenderer';
import { useDisplayCategory } from '@/components/blog/useDisplayCategory';
import { formatPostDate } from '@/components/home/blogPreviewUtils';
import StaticPageLayout from '@/components/shared/static/StaticPageLayout';
import { Container, Spinner, Text } from '@/components/ui';
import OptimisedImage from '@/components/ui/OptimisedImage';
Expand Down Expand Up @@ -109,11 +110,7 @@ export default function BlogPage() {
}, [post?.filename, isNotebook]);

// Format date
const formattedDate = new Date(post.date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
const formattedDate = formatPostDate(post.date, 'long');

if (loading) {
return (
Expand Down
18 changes: 18 additions & 0 deletions app/src/tests/unit/components/home/blogPreviewUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,21 @@ describe('formatPostDate', () => {
expect(result).toBe('Jan 12, 2026');
});
});

describe('formatPostDate month style', () => {
test('given date-only string then long month reads as the same calendar day', () => {
// When
const result = formatPostDate('2026-09-15', 'long');

// Then
expect(result).toBe('September 15, 2026');
});

test('given date-only string then short month is the default', () => {
// When
const result = formatPostDate('2026-09-15');

// Then
expect(result).toBe('Sep 15, 2026');
});
});
Loading