How to Format Dates in SharePoint Framework (SPFx)

If you’ve ever pulled a date from a SharePoint list in an SPFx web part and ended up staring at something like 2026-05-05T09:30:00Z, you know, the frustration. SharePoint returns dates in UTC ISO 8601 format, and that raw string is never something you’d want to show a user.

In this tutorial, I’ll walk you through every practical way to format dates in SPFx — from simple vanilla JavaScript to using libraries like date-fns and PnPjs. I’ll also cover time zone handling, writing dates back to SharePoint, comparing dates, handling null dates safely, and building a reusable utility file. By the end, you’ll know exactly which approach to use for which situation.

If you want to learn SharePoint Framework development, check out the complete SPFx training course.

Why Date Formatting in SPFx Is Trickier Than It Looks

Before we get into the methods, let me quickly explain why date handling in SPFx isn’t as simple as it sounds.

When you query a SharePoint list using the REST API or PnPjs, date columns come back in UTC format, like this:

2026-05-05T09:30:00Z

The problem is that the user sitting in Bengaluru or Berlin doesn’t want to see that. They want to see something like May 05, 2026 or 05/05/2026 — ideally in their own time zone.

So formatting a date in SPFx really means two things:

  • Parsing the UTC string correctly
  • Displaying it in a human-friendly format (with or without time zone conversion)

There are also a few gotchas developers run into constantly:

  • getMonth() is zero-indexed in JavaScript — November is 10, not 11
  • new Date(undefined) silently returns Invalid Date and can crash your component
  • Saving a date without specifying the time can roll it back a day for UTC+ users
  • Moment.js adds massive bundle size and is now in maintenance mode — avoid it for new SPFx projects

Let’s get into the methods.

Method 1: Using JavaScript’s Built-in Date Object

This is the simplest approach and requires zero extra libraries. If you just need basic formatting, the native JavaScript Date object plus toLocaleDateString() does the job nicely.

Basic example

Say you get this date back from SharePoint:

const rawDate = "2026-11-15T09:30:00Z";
const date = new Date(rawDate);

const formatted = date.toLocaleDateString("en-US");
console.log(formatted); // 11/15/2026

That gives you a simple US-format date. But toLocaleDateString() is way more powerful than that. You can pass an options object to control exactly how it looks.

Custom formats with Intl.DateTimeFormatOptions

const rawDate = "2026-11-15T09:30:00Z";
const date = new Date(rawDate);

const options: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "long",
day: "2-digit"
};

const formatted = date.toLocaleDateString("en-US", options);
console.log(formatted); // November 15, 2026

You can swap "long" for "short" or "numeric" for the month:

month valueOutput
"long"November
"short"Nov
"numeric"11
"2-digit"11

Formatting date AND time together

const options: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "short",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
hour12: true
};

const formatted = date.toLocaleString("en-US", options);
console.log(formatted); // Nov 15, 2026, 03:00 PM
sharepoint json date format dd-mm-yyyy

When to use this

  • You want zero extra dependencies in your project
  • You just need basic locale-aware formatting
  • Bundle size matters to you (and it should, in SPFx)

Downside: Time zone conversion requires extra work with this approach.

Check out SharePoint Framework (SPFx) Form Validation

Method 2: Write Your Own Format Function

Sometimes you need full control — maybe you want DD-MM-YYYY and nothing else. The cleanest way is to write a small utility function.

function formatDate(dateString: string): string {
const date = new Date(dateString);
const day = date.getDate().toString().padStart(2, "0");
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const year = date.getFullYear();
return `${day}-${month}-${year}`;
}

console.log(formatDate("2026-11-15T09:30:00Z")); // 15-11-2026

A couple of things to note here:

  • getMonth() is zero-indexed in JavaScript, so November is 10, not 11. That’s why I always add +1.
  • padStart(2, "0") ensures you get 05 instead of 5.

Adding time to the output

function formatDateTime(dateString: string): string {
const date = new Date(dateString);
const day = date.getDate().toString().padStart(2, "0");
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const year = date.getFullYear();
const hours = date.getHours().toString().padStart(2, "0");
const minutes = date.getMinutes().toString().padStart(2, "0");
return `${day}-${month}-${year} ${hours}:${minutes}`;
}

console.log(formatDateTime("2026-11-15T09:30:00Z")); // 15-11-2026 09:30
spfx custom date format dd-mm-yyyy

When to use this

  • You need a very specific output format
  • You’re building a reusable utility file for your SPFx project
  • You want no library overhead whatsoever

Read SPFx Web Part Audience Targeting

Method 3: Using the date-fns Library

If your project handles a lot of date manipulation — not just formatting — I’d recommend date-fns over moment.js. It’s modular, so you only import what you actually use, which keeps the bundle size down. Moment.js, in contrast, is quite heavy and is now in maintenance mode.

Install it first

npm install date-fns --save

Basic formatting

import { format } from "date-fns";

const dateFnsDate = new Date("2026-11-15T09:30:00Z");
const dateFnsFormatted = format(dateFnsDate, "dd-MM-yyyy");
console.log(dateFnsFormatted); // 15-11-2026

Common format tokens in date-fns

TokenMeaningExample
ddDay with leading zero05
dDay without leading zero5
MMMonth number with leading zero11
MMMMFull month nameNovember
MMMShort month nameNov
yyyy4-digit year2024
HH24-hour time09
hh12-hour time09
mmMinutes30
aAM/PMAM

Formatting with full date and time

import { format } from "date-fns";

const dateFnsDateTime = format(new Date("2026-11-15T09:30:00Z"), "MMMM dd, yyyy 'at' hh:mm a");
console.log(dateFnsDateTime); // November 15, 2026 at 03:00 PM
how to format date using date-fns in spfx

Date Math with date-fns

One major advantage of date-fns is the ability to do date arithmetic cleanly:

import { addDays, subMonths, differenceInDays, isPast, isAfter } from "date-fns";

const today = new Date();
const dueDate = new Date("2026-12-31T00:00:00Z");

// Add 7 days to today
const nextWeek = addDays(today, 7);

// Subtract 1 month
const lastMonth = subMonths(today, 1);

// Difference between two dates
const daysUntilDue = differenceInDays(dueDate, today);
console.log(`Days until due: ${daysUntilDue}`);

// Check if a date is in the past
const isOverdue = isPast(dueDate);
console.log(`Is overdue: ${isOverdue}`);

// Check if one date is after another
console.log(isAfter(dueDate, today)); // true or false

This is especially useful in SPFx task management web parts where you need to highlight overdue items or calculate SLA deadlines.

When to use date-fns

  • You need to do date math (add days, subtract months, compare dates, check if a date is past)
  • You want clean, tree-shakable imports
  • You don’t want to deal with moment.js’s legacy baggage

Check out SPFx Environment Variables

Method 4: Handling Time Zones Correctly

This is where most developers get tripped up. When SharePoint returns a date like 2026-11-15T09:30:00Z, the Z means UTC. If your user is in India (UTC+5:30), that’s actually 3:00 PM IST — not 9:30 AM.

There are two strategies here.

Strategy A: Use FieldValuesAsText with PnPjs

This is the simplest approach and my personal favorite for most cases. Instead of converting time zones manually, you let SharePoint do it for you by requesting FieldValuesAsText. SharePoint returns the date already formatted in the site’s regional settings time zone.

import { spfi, SPFx } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";

const sp = spfi().using(SPFx(this.context));

const items = await sp.web.lists
.getByTitle("Events")
.items
.select("Title", "EventDate", "FieldValuesAsText/EventDate")
.expand("FieldValuesAsText")();

items.forEach(item => {
// This date is already formatted per SharePoint's regional settings
const displayDate = item.FieldValuesAsText.EventDate;
console.log(displayDate); // e.g., "11/15/2026 9:30 AM"
});

No conversion, no library — SharePoint does the heavy lifting.

Strategy B: Convert UTC to a specific time zone using Intl

If you need more control, you can use the built-in Intl.DateTimeFormat with a time zone option. No extra libraries needed.

const tzDate = new Date("2026-11-15T09:30:00Z");

const formatted4 = new Intl.DateTimeFormat("en-IN", {
timeZone: "Asia/Kolkata",
year: "numeric",
month: "long",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
hour12: true
}).format(tzDate);

console.log(formatted4);

You can swap "Asia/Kolkata" with any IANA time zone string like "America/New_York" or "Europe/London".

convert utc to specific timezone spfx server

Getting the user’s site time zone dynamically

If you need to match SharePoint’s site time zone dynamically, you can read it from the page context:

const legacyCtx: any = this.context.pageContext.legacyPageContext;
const siteTimezone = legacyCtx.webTimeZoneData?.Description;
// Use this to map to IANA format and pass to date-fns-tz or Intl

Check out Migrate from Gulp based to Heft based Toolchain in SharePoint Framework (SPFx)

Method 5: Comparing Dates in SPFx

Comparing two SharePoint dates is a common requirement — especially for highlighting overdue tasks, filtering by date range, or sorting list items.

Simple Date Comparison

const date1 = new Date("2026-11-15T09:30:00Z");
const date2 = new Date("2026-12-01T09:30:00Z");

if (date1 < date2) {
console.log("date1 is earlier");
} else if (date1 > date2) {
console.log("date1 is later");
} else {
console.log("Dates are equal");
}

Check If a SharePoint Date Has Passed

function isDatePast(dateString: string | null): boolean {
if (!dateString) return false;
return new Date(dateString) < new Date();
}

// Usage in React component
const overdue = isDatePast(item.DueDate);

Sort SharePoint List Items by Date

const sortedItems = items.sort((a, b) => {
return new Date(a.Created).getTime() - new Date(b.Created).getTime();
});

This pattern is useful when you’re fetching items from multiple lists and need to merge and sort them by date on the client side.

Method 6: Handling Null and Invalid Dates Safely

SharePoint date fields can be empty, and new Date(undefined) or new Date(null) will return Invalid Date, which silently breaks your component. Always guard against this.

Safe Format Wrapper

function safeFormatDate(dateString: string | null | undefined): string {
if (!dateString) return "—";

const date = new Date(dateString);

if (isNaN(date.getTime())) return "Invalid date";

return date.toLocaleDateString("en-GB", {
day: "2-digit",
month: "short",
year: "numeric"
});
}

console.log(safeFormatDate(null)); // —
console.log(safeFormatDate("not-a-date")); // Invalid date
console.log(safeFormatDate("2026-11-15T09:30:00Z")); // 15 Nov 2026
handling invalid or null date in spfx webpart

Always use a wrapper like this when rendering dates from SharePoint list items in your React components.

Method 7: Formatting Dates for Writing Back to SharePoint

This one catches people out. When you’re reading dates, you have flexibility. But when you’re writing a date back to a SharePoint list, SharePoint expects a very specific UTC format: YYYY-MM-DDTHH:mm:ssZ.

Here’s a simple utility function for that:

function toSharePointDate(date: Date): string {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const day = date.getDate().toString().padStart(2, "0");
return `${year}-${month}-${day}T00:00:00Z`;
}

// Example: saving a date using PnPjs
const sp = spfi().using(SPFx(this.context));

await sp.web.lists.getByTitle("Tasks").items.add({
Title: "New Task",
DueDate: toSharePointDate(new Date("2026-12-31"))
});

A common gotcha here: if you’re working with a date-only field (not date+time), make sure you set the time to T00:00:00Z so the UTC conversion doesn’t accidentally roll it back to the previous day for users in UTC+ time zones.

formatting dates for writing back to sharepoint list

Method 8: Building a Reusable Date Utility File

The same methods work in SPFx extensions and across multiple web parts, but copy-pasting code everywhere is messy. The clean pattern is to centralize all your date logic in one reusable utility file.

Create a file called dateUtils.ts in your project’s utils folder:

// src/utils/dateUtils.ts

export function formatToDisplay(dateString: string | null | undefined): string {
if (!dateString) return "—";
const date = new Date(dateString);
if (isNaN(date.getTime())) return "Invalid date";
return date.toLocaleDateString("en-GB", {
day: "2-digit",
month: "short",
year: "numeric"
});
}

export function formatToDisplayWithTime(dateString: string | null | undefined): string {
if (!dateString) return "—";
const date = new Date(dateString);
if (isNaN(date.getTime())) return "Invalid date";
return date.toLocaleString("en-GB", {
day: "2-digit",
month: "short",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
hour12: true
});
}

export function formatToSharePoint(date: Date): string {
const y = date.getFullYear();
const m = (date.getMonth() + 1).toString().padStart(2, "0");
const d = date.getDate().toString().padStart(2, "0");
return `${y}-${m}-${d}T00:00:00Z`;
}

export function isDatePast(dateString: string | null | undefined): boolean {
if (!dateString) return false;
return new Date(dateString) < new Date();
}

export function daysBetween(dateString1: string, dateString2: string): number {
const d1 = new Date(dateString1);
const d2 = new Date(dateString2);
const diffMs = Math.abs(d2.getTime() - d1.getTime());
return Math.floor(diffMs / (1000 * 60 * 60 * 24));
}
convert utc to specific timezone spfx webpart

Then import wherever you need it:

import { formatToDisplay, isDatePast, daysBetween } from "../../utils/dateUtils";

const displayDate = formatToDisplay(item.Created); // 15 Nov 2026
const overdue = isDatePast(item.DueDate); // true or false
const age = daysBetween(item.Created, item.Modified); // number of days
formate date in spfx web part

This keeps your components clean and your date logic centralized, tested, and easy to maintain across the entire project.

Method 9: Formatting Dates in SPFx Extensions (ListView Command Sets / Application Customizers)

The same methods work in extensions, but you won’t have a component state to work with directly. A clean pattern is to export a reusable date utility file.

Create a file called dateUtils.ts in your project’s utils folder:

// src/utils/dateUtils.ts

export function formatToDisplay(dateString: string | null): string {
if (!dateString) return "—";
const date = new Date(dateString);
return date.toLocaleDateString("en-GB", {
day: "2-digit",
month: "short",
year: "numeric"
});
}

export function formatToSharePoint(date: Date): string {
const y = date.getFullYear();
const m = (date.getMonth() + 1).toString().padStart(2, "0");
const d = date.getDate().toString().padStart(2, "0");
return `${y}-${m}-${d}T00:00:00Z`;
}

Then import wherever you need it:

import { formatToDisplay } from "../../utils/dateUtils";

const displayDate = formatToDisplay(item.Created); // 15 Nov 2026

This keeps your components clean and your date logic centralized.

Which Method Should You Use?

ScenarioBest Approach
Simple display with locale awarenesstoLocaleDateString() with options
Specific fixed format (DD-MM-YYYY)Custom utility function
Lots of date math + formattingdate-fns
Respect SharePoint’s regional settingsFieldValuesAsText with PnPjs
Time zone-aware displayIntl.DateTimeFormat with timeZone
Writing a date back to SharePointCustom toSharePointDate() function
Null-safe display in React componentsSafe wrapper with isNaN check
Shared logic across web parts/extensionsCentralized dateUtils.ts utility file

Things to Keep in Mind

  • Never use moment.js for new SPFx projects. It’s in maintenance mode, adds significant bundle size, and date-fns or native Intl handles everything it does.
  • Always check for null/undefined before formatting. SharePoint date fields can be empty, and new Date(undefined) returns Invalid Date, which crashes things silently.
  • The UTC shift trap is real. If a user picks November 15 in a date picker and you save it as new Date("2024-11-15") without handling the time zone, it may show up as November 14 in some environments. Always set time explicitly when writing to SharePoint.
  • date-fns is tree-shakable, meaning you only pay the bundle cost for the functions you actually import — unlike moment.js, which ships the whole thing regardless.
  • Use FieldValuesAsText when you simply want to display dates as SharePoint already formats them per the site’s regional settings — it’s the lowest-effort, most reliable approach for read-only display scenarios.
  • Centralize date logic in dateUtils.ts once your project grows beyond two or three web parts. It makes maintenance and testing significantly easier.

Wrapping Up

In this guide, we covered eight practical ways to format and work with dates in SPFx — from the built-in JavaScript Date object and custom utility functions, to date-fns for date math, time zone handling with Intl.DateTimeFormat and FieldValuesAsText, comparing and sorting dates, handling null values safely, and formatting dates correctly when writing back to SharePoint.

You don’t need all of them in every project — just pick the approach that fits your situation best, and consider building a shared dateUtils.ts file as your project grows.

Try them out and let me know in the comments which method works best for you!

Also, you may like:

Power Apps functions free pdf

30 Power Apps Functions

This free guide walks you through the 30 most-used Power Apps functions with real business examples, exact syntax, and results you can see.

Download User registration canvas app

DOWNLOAD USER REGISTRATION POWER APPS CANVAS APP

Download a fully functional Power Apps Canvas App (with Power Automate): User Registration App