Of course! This is a very common point of confusion for developers working with both Java and JavaScript. The core issue is that they represent dates in fundamentally different ways.

Here’s a complete breakdown, from the core concepts to practical conversion examples.
The Core Difference: Representation
Java java.util.Date
- What it is: A wrapper around a single number: the number of milliseconds since the Unix epoch (January 1, 1970, 00:00:00 UTC).
- Key takeaway: It's just a long integer (a
long) stored inside an object. It doesn't have timezone information itself. It's an "absolute" point in time. - Problem: It's a legacy class. Its methods like
getYear(),getMonth()are deprecated and confusing (e.g.,getMonth()returns 0-11, not 1-12). For modern Java, you should usejava.time(JSR-310).
JavaScript Date
- What it is: Also based on the number of milliseconds since the Unix epoch.
- Key takeaway: It's an object that represents a single moment in time. Crucially, almost all of its "getter" methods (
getHours(),getMonth(), etc.) are based on the local timezone of the environment where the code is running. This is the most common source of bugs. - Example:
new Date().getHours()will give you the current hour in New York, London, or Tokyo, depending on where the JavaScript engine is executing.
Modern Java: The java.time Package (Since Java 8)
If you are using Java 8 or newer, always prefer the java.time package. It's designed to fix all the flaws of the old java.util.Date.
| Concept | Java (java.time) |
JavaScript (Date) |
|---|---|---|
| Absolute Point in Time | Instant |
Date object (the underlying value is a timestamp) |
| Date (Year-Month-Day) | LocalDate |
N/A (You must use Date and manage the time part) |
| Time (Hour-Minute-Second) | LocalTime |
N/A (You must use Date and manage the date part) |
| Date & Time (no timezone) | LocalDateTime |
N/A (You must use Date and manage the timezone) |
| Date & Time with Timezone | ZonedDateTime |
Date object (internally stores UTC, but getters use local timezone) |
| Timezone | ZoneId |
Intl.DateTimeFormat().resolvedOptions().timeZone (get current) or String (e.g., "America/New_York") |
| Text Format | DateTimeFormatter |
Date.prototype.toISOString(), toLocaleString(), etc. |
Conversion Scenarios
Here are the most common ways you'll need to convert between them.
Scenario A: Java to JavaScript (e.g., via a REST API)
This is the most frequent use case. Your Java backend sends a date to your JavaScript frontend.

Best Practice (using Java 8+ java.time):
-
On the Java side: Convert your
ZonedDateTime(orInstant) to an ISO 8601 string. This format is unambiguous and easy for JavaScript to parse.import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; public class JavaToJsDate { public static void main(String[] args) { // 1. Create a ZonedDateTime (e.g., current time in New York) ZonedDateTime zonedDateTime = ZonedDateTime.now(); // 2. Format it to an ISO 8601 string (e.g., "2025-10-27T10:30:00-04:00[America/New_York]") // This is the best format! It contains both the time and the timezone. DateTimeFormatter formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME; String isoString = zonedDateTime.format(formatter); System.out.println("Java -> ISO String for JS: " + isoString); // For an Instant (a point in time, no timezone info) // Use ISO_INSTANT format. It will be in UTC. String isoInstantString = ZonedDateTime.now().toInstant().format(DateTimeFormatter.ISO_INSTANT); System.out.println("Java -> ISO Instant String for JS: " + isoInstantString); } } -
On the JavaScript side: Parse the ISO string. This is the most reliable method.
// The string received from your Java backend const dateStringFromJava = "2025-10-27T10:30:00-04:00[America/New_York]"; // Parse it into a JavaScript Date object const jsDate = new Date(dateStringFromJava); console.log("JavaScript Date object:", jsDate); // Output: JavaScript Date object: 2025-10-27T14:30:00.000Z // Note: The browser automatically converts the -04:00 timezone to UTC for internal storage. // Now you can use it console.log("Year:", jsDate.getFullYear()); // 2025 console.log("Month (0-indexed):", jsDate.getMonth()); // 9 (October) console.log("Day:", jsDate.getDate()); // 27 console.log("Hours (UTC):", jsDate.getUTCHours()); // 14 console.log("Hours (local):", jsDate.getHours()); // Depends on your local timezone
Scenario B: JavaScript to Java (e.g., via a REST API)
Your frontend sends a date to your Java backend.

Best Practice (using Java 8+ java.time):
-
On the JavaScript side: Send the date as an ISO 8601 string. This is the standard.
// Get the current date and time as an ISO string // Example: "2025-10-27T14:35:12.123Z" (Z for Zulu/UTC) const isoStringForJava = new Date().toISOString(); // Send this string in your API request body console.log("JS -> ISO String for Java:", isoStringForJava); -
On the Java side: Parse the ISO string using
java.time.import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; public class JsToJavaDate { public static void main(String[] args) { // The string received from your JavaScript frontend String isoStringFromJs = "2025-10-27T14:35:12.123Z"; // 1. Parse the string into an Instant (a point in time) Instant instant = Instant.parse(isoStringFromJs); System.out.println("Java Instant: " + instant); // 2. Convert the Instant to other useful types // Get a ZonedDateTime in a specific timezone ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of("America/New_York")); System.out.println("Java ZonedDateTime (NY): " + zonedDateTime); // Get a LocalDateTime (date and time without timezone) // This is useful if you only care about the calendar date and time of day. // You need to specify a timezone to convert from Instant. ZonedDateTime zonedDateTimeTokyo = instant.atZone(ZoneId.of("Asia/Tokyo")); System.out.println("Java ZonedDateTime (Tokyo): " + zonedDateTimeTokyo); } }
Handling Legacy java.util.Date
If you're stuck with a legacy codebase that uses java.util.Date, the conversions are similar but a bit messier.
Java java.util.Date to JavaScript Date
import java.util.Date;
// A legacy Java Date object
java.util.Date javaDate = new Date(); // Represents now
// Get the underlying milliseconds since epoch
long milliseconds = javaDate.getTime();
// Pass this value to JavaScript
// In a web app, you might put this in a JSON object
String jsonPayload = "{\"timestamp\":" + milliseconds + "}";
// In JavaScript
const payload = JSON.parse('{"timestamp":1698375601234}');
// Create a Date object from the milliseconds
const jsDate = new Date(payload.timestamp);
console.log(jsDate); // Correctly represents the same moment in time
JavaScript Date to Java java.util.Date
// In JavaScript
const jsDate = new Date();
const milliseconds = jsDate.getTime();
// Send this milliseconds value to your Java backend
// e.g., in a JSON object: {"timestamp": milliseconds}
import java.util.Date;
// In Java (legacy)
long millisecondsFromJs = 1698375601234L; // Received from JS
// Create a legacy java.util.Date object
java.util.Date legacyJavaDate = new Date(millisecondsFromJs);
System.out.println("Legacy Java Date: " + legacyJavaDate);
Summary and Best Practices
- For Modern Java (8+): Use the
java.timepackage (Instant,ZonedDateTime,LocalDateTime). It's safer, clearer, and less error-prone. - For Communication (APIs): Always use the ISO 8601 format for date strings (e.g.,
"2025-10-27T10:30:00-04:00"or"2025-10-27T14:35:12.123Z"). It's a universal standard that both Java and JavaScript can parse correctly. - On the JavaScript side: Be acutely aware of the difference between local time getters (
getHours(),getMonth()) and UTC getters (getUTCHours(),getUTCMonth()). If you want to avoid timezone confusion, prefer UTC methods or use a library like Luxon or date-fns. - Avoid Legacy
java.util.Date: Only use it if you absolutely must interface with old code. For any new development,java.timeis the way to go.
