From 0bdaf96b0c338e19868cbf5561782f6f85d860e4 Mon Sep 17 00:00:00 2001 From: sunyiteng Date: Tue, 21 Apr 2026 15:17:23 +0800 Subject: [PATCH] fix(blog-list): format string dates without timezone shift --- src/blog-list/index.tsx | 53 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/src/blog-list/index.tsx b/src/blog-list/index.tsx index 290689c..16359ad 100644 --- a/src/blog-list/index.tsx +++ b/src/blog-list/index.tsx @@ -71,16 +71,59 @@ const getClassName = (...classNames: Array) => { return classNames.filter(Boolean).join(' '); }; +// 2025-6-26 16:00:00 +const ISO_DATE_PREFIX_RE = /^(\d{4})-(\d{2})-(\d{2})(?:$|[T\s])/; + +const getDatePartsFromString = (value: string) => { + const match = ISO_DATE_PREFIX_RE.exec(value.trim()); + + if (!match) { + return undefined; + } + + const [, year, month, day] = match; + + return { + year: Number(year), + month: Number(month), + day: Number(day), + }; +}; + const normalizeDate = (value?: BlogDateValue) => { if (value === undefined) { return undefined; } - const date = value instanceof Date ? value : new Date(value); + const date = + value instanceof Date + ? value + : typeof value === 'string' + ? new Date(value) + : new Date(value); return Number.isNaN(date.getTime()) ? undefined : date; }; +const formatBlogDate = ( + value: BlogDateValue | undefined, + formatter: Intl.DateTimeFormat, +) => { + if (typeof value === 'string') { + const dateParts = getDatePartsFromString(value); + + if (dateParts) { + return formatter.format( + new Date(dateParts.year, dateParts.month - 1, dateParts.day), + ); + } + } + + const date = normalizeDate(value); + + return date ? formatter.format(date) : undefined; +}; + const getPostKey = (post: BlogListItem, index: number) => { if (post.id !== undefined) { return post.id; @@ -171,7 +214,7 @@ function BlogCard({ interactive, renderInlineMarkdown, }: BlogCardProps) { - const normalizedDate = normalizeDate(post.date); + const formattedDate = formatBlogDate(post.date, dateFormatter); const isInteractive = interactive && Boolean(post.href); const hasTitle = hasContent(post.title); const hasDescription = hasContent(post.description); @@ -195,10 +238,8 @@ function BlogCard({ const cardContent = ( <> - {normalizedDate ? ( - - {dateFormatter.format(normalizedDate)} - + {formattedDate ? ( + {formattedDate} ) : null} {hasTitle ?
{post.title}
: null} {hasDescription ? (