Spring Boot PostgreSQL TimeZone Connection Error: Complete Guide
While connecting a Spring Boot application with PostgreSQL, developers may encounter an error like: FATAL: invalid value for parameter "TimeZone": "Asia/Calcutta". This issue usually happens because Java, PostgreSQL, operating system, and Docker can use different timezone identifiers.
The Problem Scenario
A typical Spring Boot datasource configuration may look like this:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/searchdb?options=-c%20TimeZone=Asia/Kolkata
username: admin
password: admin123The application starts successfully, but database connection fails with the following error:
FATAL: invalid value for parameter "TimeZone": "Asia/Calcutta"Understanding Where Timezone Comes From
A Java application can get timezone information from multiple places. The final timezone used by the application depends on priority order.
- JVM timezone (-Duser.timezone system property)
- Operating system timezone
- Container timezone when running inside Docker
- Database server timezone
- Application configuration
Checking Current Java Timezone
You can check the timezone used by your JVM using:
System.out.println(java.util.TimeZone.getDefault().getID());In this case the output was:
Asia/CalcuttaWhy Java Shows Asia/Calcutta
The operating system timezone was India Standard Time. Windows internally maps this timezone to an older Java timezone identifier called Asia/Calcutta.
PS C:\Users> Get-TimeZone
Id : India Standard Time
DisplayName : (UTC+05:30) Chennai, Kolkata, Mumbai, New DelhiEven though modern applications commonly use Asia/Kolkata, Java timezone databases may still return the backward-compatible alias Asia/Calcutta depending on the environment.
Why echo $env:TZ Shows Nothing
On Windows PowerShell, running echo $env:TZ shows nothing because the TZ environment variable is not set. Windows does not normally use the Linux TZ environment variable.
PS C:\Users> echo $env:TZ
(no output)This does not mean Windows has no timezone. Windows stores timezone information using its registry configuration, which can be checked using:
Get-TimeZoneWhy PostgreSQL Connection Failed
The PostgreSQL JDBC driver sends the JVM timezone during connection initialization. PostgreSQL validates the timezone name. In this case PostgreSQL rejected Asia/Calcutta because the server timezone database did not contain that identifier.
Caused by: org.postgresql.util.PSQLException:
FATAL: invalid value for parameter "TimeZone": "Asia/Calcutta"Hibernate then failed because it could not obtain database metadata. The Hibernate dialect error was only a secondary error.
Unable to determine Dialect without JDBC metadataImportant Debugging Rule
- First fix the PostgreSQL connection error
- Ignore secondary Hibernate errors until database connection works
- Always read the first root cause exception
Checking PostgreSQL Current Timezone
Before changing application settings, verify what timezone PostgreSQL is using.
SHOW timezone;Example output:
Asia/KolkataListing Supported PostgreSQL Timezones
PostgreSQL provides a list of supported timezone names.
SELECT name FROM pg_timezone_names
WHERE name LIKE '%Kolkata%';Asia/KolkataYou can also check whether Asia/Calcutta exists:
SELECT name FROM pg_timezone_names
WHERE name LIKE '%Calcutta%';Testing PostgreSQL Connection Outside Spring Boot
Always test the database independently before debugging Hibernate.
psql -h localhost -U admin -d searchdbAfter connecting:
SELECT now();
SHOW timezone;Docker Timezone Debugging
Containers do not always use the host machine timezone. A Docker container can have its own timezone configuration.
Check Running Containers
docker psOpen Shell Inside Container
docker exec -it <container_name> bashCheck Container Timezone
date
cat /etc/timezoneIf the container returns UTC, the application may behave differently from your local machine.
Docker Compose Timezone Configuration
For Linux based containers, timezone can be configured using the TZ environment variable.
services:
search-service:
image: search-service
environment:
TZ: Asia/KolkataHowever, setting TZ alone does not always change Java timezone. JVM applications should use JVM timezone configuration when consistency is required.
Spring Boot Datasource Fix
The database URL should use a PostgreSQL-supported timezone identifier.
spring:
datasource:
url: jdbc:postgresql://localhost:5432/searchdb?options=-c%20TimeZone=Asia/Kolkata
username: admin
password: admin123Avoid depending on the operating system timezone because it can differ between developer machines, Docker containers, and production servers.
Fixing Java JVM Timezone
The recommended way to force Java timezone is by setting the JVM system property.
-Duser.timezone=Asia/KolkataSetting JVM Option in IntelliJ IDEA
For local development, IntelliJ IDEA allows adding JVM arguments in the Run Configuration.
- Open Run menu
- Select Edit Configurations
- Select your Spring Boot application
- Open VM Options field
- Add -Duser.timezone=Asia/Kolkata
- Apply and restart application
-Duser.timezone=Asia/KolkataVerifying JVM Timezone After Fix
public class TimeZoneCheck {
public static void main(String[] args) {
System.out.println(java.util.TimeZone.getDefault().getID());
}
}Asia/KolkataWhy Not Use Hardcoded Timezone Everywhere?
Hardcoding timezone inside application code is usually not recommended because timezone is environment configuration, not business logic.
- Different users may exist in different timezones
- Production servers may run in UTC
- Cloud providers commonly use UTC
- Changing timezone should not require code changes
Production Best Practice: Use UTC Internally
Most production systems store and process timestamps using UTC. The timezone conversion should happen only at the user interface or API response layer.
- Database stores timestamps in UTC
- Backend services communicate using UTC
- Frontend converts UTC into user timezone
- Reports convert timestamps based on user requirements
Why UTC Is Preferred in Production
- Avoids timezone differences between servers
- Works consistently across cloud providers
- Avoids daylight saving problems
- Simplifies distributed systems
- Makes log comparison easier
Recommended Production JVM Configuration
For production servers, configure timezone outside the application code.
java -Duser.timezone=UTC -jar search-service.jarIf your business requires India Standard Time everywhere, use:
java -Duser.timezone=Asia/Kolkata -jar search-service.jarDocker Production Configuration
The JVM option can be passed using JAVA_TOOL_OPTIONS or JAVA_OPTS.
services:
search-service:
image: search-service:latest
environment:
JAVA_TOOL_OPTIONS: -Duser.timezone=Asia/KolkataThis approach avoids rebuilding the Docker image when timezone changes.
Docker Command Example
docker run \
-e JAVA_TOOL_OPTIONS='-Duser.timezone=Asia/Kolkata' \
-p 8080:8080 \
search-serviceKubernetes Production Configuration
env:
- name: JAVA_TOOL_OPTIONS
value: "-Duser.timezone=UTC"Complete Fixed Spring Boot Configuration
server:
port: 8080
spring:
application:
name: search-service
datasource:
url: jdbc:postgresql://localhost:5432/searchdb?options=-c%20TimeZone=Asia/Kolkata
username: admin
password: admin123
jpa:
hibernate:
ddl-auto: create
data:
redis:
host: localhost
port: 6379
elasticsearch:
uris: http://localhost:9200Complete Debugging Checklist
- Check operating system timezone
- Check JVM timezone using TimeZone.getDefault()
- Check Docker container timezone
- Check PostgreSQL timezone using SHOW timezone
- Verify PostgreSQL supports the timezone name
- Use Asia/Kolkata instead of unsupported aliases
- Set JVM timezone using -Duser.timezone
- Restart application after changing VM options
Common Mistakes
- Changing only Windows timezone and expecting Java to change
- Using TZ environment variable for JVM applications
- Hardcoding timezone in Java business code
- Ignoring the first database connection error
- Debugging Hibernate dialect error before fixing database connection
Final Fixed Solution For This Issue
- Root cause: Java returned Asia/Calcutta from Windows timezone mapping
- PostgreSQL rejected Asia/Calcutta timezone identifier
- Use Asia/Kolkata in PostgreSQL configuration
- Set JVM timezone using -Duser.timezone=Asia/Kolkata
- For production, prefer UTC unless business requires another timezone
Final Summary
- Timezone issues happen because multiple systems manage timezone independently
- Windows timezone, Java timezone, Docker timezone, and PostgreSQL timezone can differ
- The PostgreSQL connection failed because of an unsupported timezone identifier
- The Hibernate dialect error was only a secondary failure
- JVM timezone should be configured externally using system properties
- Production systems should normally store and process time using UTC