diff --git a/examples/datetime-timezone/README.rst b/examples/datetime-timezone/README.rst
new file mode 100644
index 000000000..c570419fd
--- /dev/null
+++ b/examples/datetime-timezone/README.rst
@@ -0,0 +1,25 @@
+This example shows how to make Flask-Admin display all datetime fields in client's
+timezone.
+Timezone conversion is handled by the frontend in /static/js/timezone.js, but an
+automatic post request to /set_timezone is done so that flask session can store the
+client's timezone and save datetime inputs in the correct timezone.
+
+To run this example:
+
+1. Clone the repository::
+
+ git clone https://github.com/pallets-eco/flask-admin.git
+ cd flask-admin
+
+2. Create and activate a virtual environment::
+
+ virtualenv env
+ source env/bin/activate
+
+3. Install requirements::
+
+ pip install -r 'examples/datetime-timezone/requirements.txt'
+
+4. Run the application::
+
+ python examples/datetime-timezone/app.py
diff --git a/examples/datetime-timezone/__init__.py b/examples/datetime-timezone/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/examples/datetime-timezone/app.py b/examples/datetime-timezone/app.py
new file mode 100644
index 000000000..0d113ab73
--- /dev/null
+++ b/examples/datetime-timezone/app.py
@@ -0,0 +1,126 @@
+from datetime import datetime
+from zoneinfo import ZoneInfo
+
+from flask import Flask, request, session, jsonify
+from flask_sqlalchemy import SQLAlchemy
+from markupsafe import Markup
+from sqlalchemy import DateTime, String
+from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
+
+from flask_admin import Admin
+from flask_admin.contrib.sqla import ModelView
+from flask_admin.model import typefmt
+
+
+# model
+class Base(DeclarativeBase):
+ pass
+
+
+# app
+app = Flask(__name__)
+app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///default.sqlite"
+# Create dummy secret key so we can use sessions
+app.config['SECRET_KEY'] = '123456789'
+db = SQLAlchemy(model_class=Base)
+db.init_app(app)
+
+
+class Article(db.Model):
+ id: Mapped[int] = mapped_column(primary_key=True)
+ text: Mapped[str] = mapped_column(String(30))
+ last_edit: Mapped[datetime] = mapped_column(DateTime(timezone=True))
+
+
+# admin
+def date_format(view, value):
+ """
+ Ensure consistent date format and inject class for timezone.js parser.
+ """
+ if value is None:
+ return ''
+ return Markup(
+ f'{value.strftime("%Y-%m-%d %H:%M:%S")}'
+ )
+
+
+MY_DEFAULT_FORMATTERS = dict(typefmt.BASE_FORMATTERS)
+MY_DEFAULT_FORMATTERS.update({
+ datetime: date_format,
+})
+
+
+class TimezoneAwareModelView(ModelView):
+ column_type_formatters = MY_DEFAULT_FORMATTERS
+ extra_js = ['/static/js/timezone.js']
+
+ def on_model_change(self, form, model, is_created):
+ """
+ Save datetime fields after converting from session['timezone'] to UTC.
+ """
+ user_timezone = session["timezone"]
+
+ for field_name, field_value in form.data.items():
+ if isinstance(field_value, datetime):
+ # Convert naive datetime to timezone-aware datetime
+ aware_time = field_value.replace(tzinfo=ZoneInfo(user_timezone))
+
+ # Convert the time to UTC
+ utc_time = aware_time.astimezone(ZoneInfo('UTC'))
+
+ # Assign the UTC time to the model
+ setattr(model, field_name, utc_time)
+
+ super(TimezoneAwareModelView, self).on_model_change(form, model, is_created)
+
+
+# inherit TimeZoneAwareModelView to make any admin page timezone-aware
+class TimezoneAwareBlogModelView(TimezoneAwareModelView):
+ column_labels = {
+ "last_edit": "Last Edit (local time)",
+ }
+
+
+# compare with regular ModelView to display data as saved on db
+class BlogModelView(ModelView):
+ column_labels = {
+ "last_edit": "Last Edit (UTC)",
+ }
+
+
+# Flask views
+@app.route('/')
+def index():
+ return 'Click me to get to Admin!'
+
+
+@app.route('/set_timezone', methods=['POST'])
+def set_timezone():
+ """
+ Save timezone to session so that datetime inputs can be correctly converted to UTC.
+ """
+ session.permanent = True
+ timezone = request.get_json()
+ if timezone:
+ session['timezone'] = timezone
+ return jsonify({'message': 'Timezone set successfully'}), 200
+ else:
+ return jsonify({'error': 'Invalid timezone'}), 400
+
+
+# create db on the fly
+with app.app_context():
+ Base.metadata.drop_all(db.engine)
+ Base.metadata.create_all(db.engine)
+ db.session.add(Article(text="Written at 9:00 UTC",
+ last_edit=datetime(2024, 8, 8, 9, 0, 0)))
+ db.session.commit()
+ admin = Admin(app, name='microblog')
+ admin.add_view(
+ BlogModelView(Article, db.session, name="Article", endpoint="article"))
+ admin.add_view(
+ TimezoneAwareBlogModelView(Article, db.session, name="Timezone Aware Article",
+ endpoint="timezone_aware_article"))
+
+if __name__ == '__main__':
+ app.run(debug=True)
diff --git a/examples/datetime-timezone/requirements.txt b/examples/datetime-timezone/requirements.txt
new file mode 100644
index 000000000..f248b7ae2
--- /dev/null
+++ b/examples/datetime-timezone/requirements.txt
@@ -0,0 +1,2 @@
+Flask-Admin
+flask-sqlalchemy
diff --git a/examples/datetime-timezone/static/js/timezone.js b/examples/datetime-timezone/static/js/timezone.js
new file mode 100644
index 000000000..2054cb763
--- /dev/null
+++ b/examples/datetime-timezone/static/js/timezone.js
@@ -0,0 +1,38 @@
+// post client's timezone so that backend can correctly convert datetime inputs to UTC
+fetch('/set_timezone', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(Intl.DateTimeFormat().resolvedOptions().timeZone)
+})
+
+
+// convert all datetime fields to client timezone
+function localizeDateTimes() {
+ const inputsOrSpans = document.querySelectorAll('input[data-date-format], span.timezone-aware');
+
+ inputsOrSpans.forEach(element => {
+ let localizedTime;
+
+ const isInput = element.tagName.toLowerCase() === 'input'
+ // Check if the element is an input or a span
+ if (isInput) {
+ // For input elements, use the value attribute
+ localizedTime = new Date(element.getAttribute("value") + "Z");
+ } else {
+ // For span elements, use the text content
+ localizedTime = new Date(element.textContent.trim() + "Z");
+ }
+
+ const formattedTime = moment(localizedTime).format('YYYY-MM-DD HH:mm:ss');
+
+ if (isInput) {
+ element.setAttribute("value", formattedTime);
+ } else {
+ element.textContent = formattedTime;
+ }
+ });
+}
+
+localizeDateTimes();