diff --git a/AUTHORS b/AUTHORS
index 4bbaba2..40d7f58 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -137,7 +137,10 @@ Contributors:
     * Chris Rose (offbyone/offby1)
     * Mathieu Dupuy (deronnax)
     * Chris Novakovic
+    * Max Smolin (maximsmol)
     * Josh Lynch (josh-lynch)
+    * Fabio (3ximus)
+    * Doug Harris (dougharris)
 
 Creator:
 --------
diff --git a/changelog.rst b/changelog.rst
index 0b219ea..dcf886a 100644
--- a/changelog.rst
+++ b/changelog.rst
@@ -1,3 +1,10 @@
+4.3.0 (2025-03-22)
+==================
+
+Features
+--------
+* The session time zone setting is set to the system time zone by default
+
 4.2.0 (2025-03-06)
 ==================
 
@@ -5,6 +12,8 @@ Features
 --------
 * Add a `--ping` command line option; allows pgcli to replace `pg_isready`
 * Changed the packaging metadata from setup.py to pyproject.toml
+* Add bash completion for services defined in the service file `~/.pg_service.conf`
+* Added support for per-column date/time formatting using `column_date_formats` in config
 
 Bug fixes:
 ----------
diff --git a/debian/changelog b/debian/changelog
index 9ff7998..82e3da3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+pgcli (4.3.0-1) sid; urgency=medium
+
+  * Merging upstream version 4.3.0.
+
+ -- Daniel Baumann <daniel@debian.org>  Mon, 24 Mar 2025 15:47:46 +0100
+
 pgcli (4.2.0-2) sid; urgency=medium
 
   * Using codename instead of suitename in changelog.
diff --git a/pgcli-completion.bash b/pgcli-completion.bash
index 3549b56..620563d 100644
--- a/pgcli-completion.bash
+++ b/pgcli-completion.bash
@@ -3,9 +3,9 @@ _pg_databases()
     # -w was introduced in 8.4, https://launchpad.net/bugs/164772
     # "Access privileges" in output may contain linefeeds, hence the NF > 1
     COMPREPLY=( $( compgen -W "$( psql -AtqwlF $'\t' 2>/dev/null | \
-	    awk 'NF > 1 { print $1 }' )" -- "$cur" ) )
+        awk 'NF > 1 { print $1 }' )" -- "$cur" ) )
 }
-                                                                                                               
+
 _pg_users()
 {
     # -w was introduced in 8.4, https://launchpad.net/bugs/164772
@@ -13,12 +13,23 @@ _pg_users()
         template1 2>/dev/null )" -- "$cur" ) )
     [[ ${#COMPREPLY[@]} -eq 0 ]] && COMPREPLY=( $( compgen -u -- "$cur" ) )
 }
-  
+
+_pg_services()
+{
+    # return list of available services
+    local services
+    if [[ -f "$HOME/.pg_service.conf" ]]; then
+        services=$(grep -oP '(?<=^\[).*?(?=\])' "$HOME/.pg_service.conf")
+    fi
+    local suffix="${cur#*=}"
+    COMPREPLY=( $(compgen -W "$services" -- "$suffix") )
+}
+
 _pgcli()
 {
     local cur prev words cword
     _init_completion -s || return
-	
+
     case $prev in
         -h|--host)
             _known_hosts_real "$cur"
@@ -39,23 +50,27 @@ _pgcli()
     esac
 
     case "$cur" in
-	    --*)
-        	# return list of available options
-       		COMPREPLY=( $( compgen -W '--host --port --user --password --no-password
- 			              --single-connection --version --dbname --pgclirc --dsn
-  			            --row-limit --help' -- "$cur" ) )
-        [[ $COMPREPLY == *= ]] && compopt -o nospace
-		    return 0
-		    ;;
-	    -)
-		    # only complete long options
-		    compopt -o nospace
-		    COMPREPLY=( -- )
-		    return 0
-		    ;;
-	    *)
+        service=*)
+            _pg_services
+            return 0
+            ;;
+        --*)
+            # return list of available options
+            COMPREPLY=( $( compgen -W '--host --port --user --password --no-password
+                --single-connection --version --dbname --pgclirc --dsn
+                --row-limit --help' -- "$cur" ) )
+            [[ $COMPREPLY == *= ]] && compopt -o nospace
+            return 0
+            ;;
+        -)
+            # only complete long options
+            compopt -o nospace
+            COMPREPLY=( -- )
+            return 0
+            ;;
+        *)
             # return list of available databases
-        	_pg_databases 
+            _pg_databases
     esac
-} && 
+} &&
 complete -F _pgcli pgcli
diff --git a/pgcli/__init__.py b/pgcli/__init__.py
index 0fd7811..111dc91 100644
--- a/pgcli/__init__.py
+++ b/pgcli/__init__.py
@@ -1 +1 @@
-__version__ = "4.2.0"
+__version__ = "4.3.0"
diff --git a/pgcli/main.py b/pgcli/main.py
index d4c6dbf..0765efb 100644
--- a/pgcli/main.py
+++ b/pgcli/main.py
@@ -1,3 +1,4 @@
+from zoneinfo import ZoneInfoNotFoundError
 from configobj import ConfigObj, ParseError
 from pgspecial.namedqueries import NamedQueries
 from .config import skip_initial_comment
@@ -19,10 +20,15 @@ from time import time, sleep
 from typing import Optional
 
 from cli_helpers.tabular_output import TabularOutputFormatter
-from cli_helpers.tabular_output.preprocessors import align_decimals, format_numbers
+from cli_helpers.tabular_output.preprocessors import (
+    align_decimals,
+    format_numbers,
+    format_timestamps,
+)
 from cli_helpers.utils import strip_ansi
 from .explain_output_formatter import ExplainOutputFormatter
 import click
+import tzlocal
 
 try:
     import setproctitle
@@ -111,12 +117,13 @@ MetaQuery.__new__.__defaults__ = ("", False, 0, 0, False, False, False, False)
 
 OutputSettings = namedtuple(
     "OutputSettings",
-    "table_format dcmlfmt floatfmt missingval expanded max_width case_function style_output max_field_width",
+    "table_format dcmlfmt floatfmt column_date_formats missingval expanded max_width case_function style_output max_field_width",
 )
 OutputSettings.__new__.__defaults__ = (
     None,
     None,
     None,
+    None,
     "<null>",
     False,
     None,
@@ -264,6 +271,7 @@ class PGCli:
         self.on_error = c["main"]["on_error"].upper()
         self.decimal_format = c["data_formats"]["decimal"]
         self.float_format = c["data_formats"]["float"]
+        self.column_date_formats = c["column_date_formats"]
         auth.keyring_initialize(c["main"].as_bool("keyring"), logger=self.logger)
         self.show_bottom_toolbar = c["main"].as_bool("show_bottom_toolbar")
 
@@ -1179,6 +1187,7 @@ class PGCli:
                 table_format=self.table_format,
                 dcmlfmt=self.decimal_format,
                 floatfmt=self.float_format,
+                column_date_formats=self.column_date_formats,
                 missingval=self.null_string,
                 expanded=expanded,
                 max_width=max_width,
@@ -1593,9 +1602,9 @@ def cli(
     if list_databases or ping_database:
         database = "postgres"
 
+    cfg = load_config(pgclirc, config_full_path)
     if dsn != "":
         try:
-            cfg = load_config(pgclirc, config_full_path)
             dsn_config = cfg["alias_dsn"][dsn]
         except KeyError:
             click.secho(
@@ -1624,6 +1633,55 @@ def cli(
     else:
         pgcli.connect(database, host, user, port)
 
+    if "use_local_timezone" not in cfg["main"] or cfg["main"].as_bool(
+        "use_local_timezone"
+    ):
+        server_tz = pgcli.pgexecute.get_timezone()
+
+        def echo_error(msg: str):
+            click.secho(
+                "Failed to determine the local time zone",
+                err=True,
+                fg="yellow",
+            )
+            click.secho(
+                msg,
+                err=True,
+                fg="yellow",
+            )
+            click.secho(
+                f"Continuing with the default time zone as preset by the server ({server_tz})",
+                err=True,
+                fg="yellow",
+            )
+            click.secho(
+                "Set `use_local_timezone = False` in the config to avoid trying to override the server time zone\n",
+                err=True,
+                dim=True,
+            )
+
+        local_tz = None
+        try:
+            local_tz = tzlocal.get_localzone_name()
+
+            if local_tz is None:
+                echo_error("No local time zone configuration found\n")
+            else:
+                click.secho(
+                    f"Using local time zone {local_tz} (server uses {server_tz})",
+                    fg="green",
+                )
+                click.secho(
+                    "Use `set time zone <TZ>` to override, or set `use_local_timezone = False` in the config",
+                    dim=True,
+                )
+
+                pgcli.pgexecute.set_timezone(local_tz)
+        except ZoneInfoNotFoundError as e:
+            # e.args[0] is the pre-formatted message which includes a list
+            # of conflicting sources
+            echo_error(e.args[0])
+
     if list_databases:
         cur, headers, status = pgcli.pgexecute.full_databases()
 
@@ -1830,6 +1888,7 @@ def format_output(title, cur, headers, status, settings, explain_mode=False):
         "missing_value": settings.missingval,
         "integer_format": settings.dcmlfmt,
         "float_format": settings.floatfmt,
+        "column_date_formats": settings.column_date_formats,
         "preprocessors": (format_numbers, format_arrays),
         "disable_numparse": True,
         "preserve_whitespace": True,
@@ -1839,6 +1898,9 @@ def format_output(title, cur, headers, status, settings, explain_mode=False):
     if not settings.floatfmt:
         output_kwargs["preprocessors"] = (align_decimals,)
 
+    if settings.column_date_formats:
+        output_kwargs["preprocessors"] += (format_timestamps,)
+
     if table_format == "csv":
         # The default CSV dialect is "excel" which is not handling newline values correctly
         # Nevertheless, we want to keep on using "excel" on Windows since it uses '\r\n'
diff --git a/pgcli/pgclirc b/pgcli/pgclirc
index dd8b15f..be10610 100644
--- a/pgcli/pgclirc
+++ b/pgcli/pgclirc
@@ -191,6 +191,10 @@ enable_pager = True
 # Use keyring to automatically save and load password in a secure manner
 keyring = True
 
+# Automatically set the session time zone to the local time zone
+# If unset, uses the server's time zone, which is the Postgres default
+use_local_timezone = True
+
 # Custom colors for the completion menu, toolbar, etc.
 [colors]
 completion-menu.completion.current = 'bg:#ffffff #000000'
@@ -240,3 +244,8 @@ output.null = "#808080"
 [data_formats]
 decimal = ""
 float = ""
+
+# Per column formats for date/timestamp columns
+[column_date_formats]
+# use strftime format, e.g.
+# created = "%Y-%m-%d"
diff --git a/pgcli/pgexecute.py b/pgcli/pgexecute.py
index e091757..4e7c637 100644
--- a/pgcli/pgexecute.py
+++ b/pgcli/pgexecute.py
@@ -881,3 +881,16 @@ class PGExecute:
 
     def explain_prefix(self):
         return "EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON) "
+
+    def get_timezone(self) -> str:
+        query = psycopg.sql.SQL("show time zone")
+        with self.conn.cursor() as cur:
+            cur.execute(query)
+            return cur.fetchone()[0]
+
+    def set_timezone(self, timezone: str):
+        query = psycopg.sql.SQL("set time zone {}").format(
+            psycopg.sql.Identifier(timezone)
+        )
+        with self.conn.cursor() as cur:
+            cur.execute(query)
diff --git a/pyproject.toml b/pyproject.toml
index d714282..6c73602 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -34,12 +34,13 @@ dependencies = [
     "psycopg-binary >= 3.0.14; sys_platform == 'win32'",
     "sqlparse >=0.3.0,<0.6",
     "configobj >= 5.0.6",
-    "cli_helpers[styles] >= 2.2.1",
+    "cli_helpers[styles] >= 2.4.0",
     # setproctitle is used to mask the password when running `ps` in command line.
     # But this is not necessary in Windows since the password is never shown in the
     # task manager. Also setproctitle is a hard dependency to install in Windows,
     # so we'll only install it if we're not in Windows.
     "setproctitle >= 1.1.9; sys_platform != 'win32' and 'CYGWIN' not in sys_platform",
+    "tzlocal >= 5.2",
 ]
 dynamic = ["version"]
 
diff --git a/release.py b/release.py
index 42a72a9..ad6a957 100644
--- a/release.py
+++ b/release.py
@@ -2,10 +2,10 @@
 """A script to publish a release of pgcli to PyPI."""
 
 import io
-from optparse import OptionParser
 import re
 import subprocess
 import sys
+from optparse import OptionParser
 
 import click
 
@@ -66,7 +66,8 @@ def create_git_tag(tag_name):
 
 
 def create_distribution_files():
-    run_step("python", "setup.py", "clean", "--all", "sdist", "bdist_wheel")
+    run_step("rm", "-rf", "dist/")
+    run_step("python", "-m", "build")
 
 
 def upload_distribution_files():
@@ -91,11 +92,11 @@ if __name__ == "__main__":
     if DEBUG:
         subprocess.check_output = lambda x: x
 
-    checks = [
-        "Have you updated the AUTHORS file?",
-        "Have you updated the `Usage` section of the README?",
-    ]
-    checklist(checks)
+    # checks = [
+    #     "Have you updated the AUTHORS file?",
+    #     "Have you updated the `Usage` section of the README?",
+    # ]
+    # checklist(checks)
 
     ver = version("pgcli/__init__.py")
     print("Releasing Version:", ver)
diff --git a/tests/test_main.py b/tests/test_main.py
index 3683d49..102ebcd 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -76,6 +76,57 @@ def test_format_output():
     assert list(results) == expected
 
 
+def test_column_date_formats():
+    settings = OutputSettings(
+        table_format="psql",
+        column_date_formats={
+            "date_col": "%Y-%m-%d",
+            "datetime_col": "%I:%M:%S %m/%d/%y",
+        },
+    )
+    data = [
+        ("name1", "2024-12-13T18:32:22", "2024-12-13T19:32:22", "2024-12-13T20:32:22"),
+        ("name2", "2025-02-13T02:32:22", "2025-02-13T02:32:22", "2025-02-13T02:32:22"),
+    ]
+    headers = ["name", "date_col", "datetime_col", "unchanged_col"]
+
+    results = format_output("Title", data, headers, "test status", settings)
+    expected = [
+        "Title",
+        "+-------+------------+-------------------+---------------------+",
+        "| name  | date_col   | datetime_col      | unchanged_col       |",
+        "|-------+------------+-------------------+---------------------|",
+        "| name1 | 2024-12-13 | 07:32:22 12/13/24 | 2024-12-13T20:32:22 |",
+        "| name2 | 2025-02-13 | 02:32:22 02/13/25 | 2025-02-13T02:32:22 |",
+        "+-------+------------+-------------------+---------------------+",
+        "test status",
+    ]
+    assert list(results) == expected
+
+
+def test_no_column_date_formats():
+    """Test that not setting any column date formats returns unaltered datetime columns"""
+    settings = OutputSettings(table_format="psql")
+    data = [
+        ("name1", "2024-12-13T18:32:22", "2024-12-13T19:32:22", "2024-12-13T20:32:22"),
+        ("name2", "2025-02-13T02:32:22", "2025-02-13T02:32:22", "2025-02-13T02:32:22"),
+    ]
+    headers = ["name", "date_col", "datetime_col", "unchanged_col"]
+
+    results = format_output("Title", data, headers, "test status", settings)
+    expected = [
+        "Title",
+        "+-------+---------------------+---------------------+---------------------+",
+        "| name  | date_col            | datetime_col        | unchanged_col       |",
+        "|-------+---------------------+---------------------+---------------------|",
+        "| name1 | 2024-12-13T18:32:22 | 2024-12-13T19:32:22 | 2024-12-13T20:32:22 |",
+        "| name2 | 2025-02-13T02:32:22 | 2025-02-13T02:32:22 | 2025-02-13T02:32:22 |",
+        "+-------+---------------------+---------------------+---------------------+",
+        "test status",
+    ]
+    assert list(results) == expected
+
+
 def test_format_output_truncate_on():
     settings = OutputSettings(
         table_format="psql", dcmlfmt="d", floatfmt="g", max_field_width=10