杰瑞科技汇

Java.sql.Timestamp与Date有何区别?

Of course! Let's dive deep into java.sql.Timestamp. This class has a long and somewhat controversial history in the Java ecosystem, but understanding it is crucial for any Java developer working with databases.

Java.sql.Timestamp与Date有何区别?-图1
(图片来源网络,侵删)

What is java.sql.Timestamp?

java.sql.Timestamp is a class in the java.sql package that extends java.util.Date. Its primary purpose is to represent a point in time that can be mapped to the SQL TIMESTAMP data type, which is capable of storing both date and time with nanosecond precision.

It was introduced to address a limitation in the original java.util.Date class, which only had millisecond precision.


Key Characteristics

  1. Extends java.util.Date: This is the source of most of its historical problems. It inherits the Date API, which has design flaws like using 0-based months and a year starting from 1900.
  2. Nanosecond Precision: Its main feature. While java.util.Date stores time as milliseconds since the "epoch" (January 1, 1970, 00:00:00 GMT), Timestamp adds nanoseconds. It stores:
    • Milliseconds (inherited from Date).
    • Nanoseconds (stored in a separate int field).
  3. Database Interaction: It's the standard type used by JDBC (Java Database Connectivity) to handle TIMESTAMP, DATETIME, and TIMESTAMP WITH TIME ZONE columns from databases.
  4. Legacy API: It's part of the old java.sql package, which is considered legacy. Modern Java development prefers the java.time package.

Core Methods and Fields

Here are the most important parts of the Timestamp API:

Method/Field Description
Timestamp(long time) Constructor. Creates a Timestamp object using a millisecond value. The nanoseconds part will be set to 0.
Timestamp(int year, ...) Legacy Constructor. Creates a Timestamp from individual date/time components. Avoid this. It uses the flawed Date constructor (year-1900, month-1, etc.).
setNanos(int n) Sets the nanos field (0 to 999,999,999).
int getNanos() Gets the nanos field.
valueOf(String s) Static Factory Method. Parses a String (e.g., "2007-12-23 09:01:06.123456789") into a Timestamp. This is the recommended way to create a Timestamp from a string.
toString() Returns a String in the format yyyy-MM-dd HH:mm:ss.nnnnnnnnn.
getTime() Inherited from Date. Returns the number of milliseconds since the epoch. Be careful! This truncates nanoseconds.
toLocalDateTime() Modern Method (Java 8+). Converts this Timestamp to a java.time.LocalDateTime, which is the recommended modern way to handle date-time.

The Problem: Why is java.sql.Timestamp Considered "Bad"?

The main issue is its confusing inheritance from java.util.Date.

Java.sql.Timestamp与Date有何区别?-图2
(图片来源网络,侵删)
  1. State Inconsistency: A Timestamp object has two parts of state: the milliseconds inherited from Date and the nanos in its own field. If you modify the milliseconds using Date methods (like setTime()), the nanos field is not updated, and vice-versa. This can lead to subtle bugs.
  2. Confusing API: Because it extends Date, you can accidentally use Date methods on a Timestamp object, leading to unexpected behavior. For example, equals() and before()/after() from the Date class compare only the millisecond part, ignoring the nanoseconds.
  3. Legacy Design: The entire java.util.Date/java.sql.Date/java.sql.Timestamp family is based on a mutable, flawed design. The modern java.time package is immutable and far superior.

Example of the Inconsistency Problem:

import java.sql.Timestamp;
public class TimestampProblem {
    public static void main(String[] args) {
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        ts.setNanos(123456789); // Set nanoseconds
        System.out.println("Original Timestamp: " + ts);
        System.out.println("Nanos (getNanos): " + ts.getNanos()); // Prints 123456789
        // Now, use a Date method to modify the milliseconds
        ts.setTime(ts.getTime() + 1000); // Add one second
        System.out.println("After setTime(): " + ts);
        // The nanos field is NOT reset! It's still 123456789, which is illogical.
        System.out.println("Nanos (getNanos) after setTime(): " + ts.getNanos()); // Still prints 123456789
    }
}

The Modern Solution: java.time (Java 8+)

The Java 8 release introduced the java.time package, which is now the official, recommended way to handle date and time in Java. It's inspired by Joda-Time and is designed to be immutable and thread-safe.

The key classes are:

  • LocalDateTime: Represents a date and time without a time zone (e.g., 2025-10-27T10:15:30). Perfect for representing a TIMESTAMP from a database.
  • Instant: Represents an instantaneous point on the timeline in UTC. Good for storing in databases or for low-level system time.
  • ZonedDateTime: Represents a date and time with a time zone.

How to Use java.time with JDBC (JDBC 4.2+)

Modern JDBC drivers have built-in support for java.time types, which is much cleaner than using Timestamp.

Java.sql.Timestamp与Date有何区别?-图3
(图片来源网络,侵删)

Setting a Parameter (Inserting/Updating)

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.LocalDateTime;
// Assume 'conn' is a valid Connection object
String sql = "INSERT INTO events (event_name, event_time) VALUES (?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setString(1, "Java Conference");
    // Set the LocalDateTime directly. The driver handles the conversion!
    pstmt.setObject(2, LocalDateTime.of(2025, 12, 25, 15, 30, 0));
    pstmt.executeUpdate();
}

Retrieving a Result (Querying)

import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
// Assume 'rs' is a valid ResultSet from a query
try (ResultSet rs = ...) {
    if (rs.next()) {
        // Get the value as a LocalDateTime directly.
        LocalDateTime eventTime = rs.getObject("event_time", LocalDateTime.class);
        System.out.println("Event Time: " + eventTime);
    }
}

Conversion Between Timestamp and java.time

Sometimes you have to work with legacy code or older JDBC drivers. Here’s how to convert.

Timestamp to LocalDateTime

import java.sql.Timestamp;
import java.time.LocalDateTime;
Timestamp ts = Timestamp.valueOf("2025-10-27 10:00:00.123456789");
// The recommended way (Java 8+)
LocalDateTime ldt = ts.toLocalDateTime();
System.out.println(ldt); // Outputs: 2025-10-27T10:00:00.123456789

LocalDateTime to Timestamp

import java.sql.Timestamp;
import java.time.LocalDateTime;
LocalDateTime ldt = LocalDateTime.now();
// The recommended way
Timestamp ts = Timestamp.valueOf(ldt);
System.out.println(ts); // Outputs a timestamp string with nanoseconds

Summary and Best Practices

Aspect java.sql.Timestamp java.time.LocalDateTime (Modern)
Package java.sql (Legacy) java.time (Modern, Java 8+)
Precision Nanoseconds Nanoseconds
Mutability Mutable (Flawed) Immutable (Safe)
Time Zone None None
Primary Use Legacy JDBC interaction. Primary for application logic.
JDBC Usage Required for old drivers. Recommended for JDBC 4.2+ drivers. Use setObject() and getObject().

Final Recommendation:

  1. For New Code: Avoid java.sql.Timestamp. Use java.time types like LocalDateTime exclusively in your application logic.
  2. For JDBC: Use pstmt.setObject(..., myLocalDateTime) and rs.getObject(..., LocalDateTime.class). It's cleaner, less error-prone, and type-safe.
  3. For Legacy Code: When you absolutely must interact with Timestamp, convert it to a java.time object immediately (ts.toLocalDateTime()) to work with it in your modern application. Only convert back to Timestamp at the last moment when you need to interact with an old system or database driver.
分享:
扫描分享到社交APP
上一篇
下一篇