杰瑞科技汇

MySQL与Java日期如何正确转换?

Of course! Working with dates and times in MySQL and Java is a common but often tricky task due to the differences in how they handle date-time data. The key is to use the modern, standard Java 8 java.time package and the corresponding java.sql types.

MySQL与Java日期如何正确转换?-图1
(图片来源网络,侵删)

Here’s a comprehensive guide covering the best practices, common pitfalls, and complete code examples.


The Core Problem: Mismatched Data Types

  • Java: Has several date/time classes. The modern, recommended ones are in java.time (e.g., LocalDate, LocalDateTime, ZonedDateTime). Older legacy classes like java.util.Date and java.sql.Date are now discouraged for new code.
  • MySQL: Has several date/time types: DATE, TIME, DATETIME, TIMESTAMP, and YEAR.

The goal is to correctly translate a Java object into a format MySQL understands, and vice-versa.

The Golden Rule: Use PreparedStatement and ResultSet Methods

Never format dates into strings and use them in SQL queries (e.g., INSERT INTO table (my_date) VALUES ('2025-10-27')). This is inefficient, error-prone, and vulnerable to SQL injection.

Always use PreparedStatement.setXXX() methods and ResultSet.getXXX() methods. They handle the conversion for you safely and correctly.

MySQL与Java日期如何正确转换?-图2
(图片来源网络,侵删)

Mapping Java java.time to MySQL Types

This is the recommended approach for any new application.

Java Type (java.time) MySQL Type Description & Usage
LocalDate DATE Represents a date without time (year, month, day). Perfect for birthdays, anniversaries, etc.
LocalTime TIME Represents a time without a date (hour, minute, second, nanosecond).
LocalDateTime DATETIME Represents a date and time, but without a time zone. This is the most common type for storing events, log entries, etc.
ZonedDateTime TIMESTAMP Represents a date and time with a time zone. Crucially, MySQL's TIMESTAMP type is time-zone aware and is stored in UTC. It's converted to the server's time zone for display. This is ideal for "wall clock" times that should be consistent across servers.

How to Set Data (Java -> MySQL)

You use PreparedStatement.setObject() or PreparedStatement.setTimestamp().

import java.sql.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class MysqlJavaDateInsert {
    public static void main(String[] args) {
        String jdbcUrl = "jdbc:mysql://localhost:3306/your_database";
        String user = "your_user";
        String password = "your_password";
        String insertSql = "INSERT INTO events (event_name, event_date, event_datetime, event_timestamp) VALUES (?, ?, ?, ?)";
        try (Connection conn = DriverManager.getConnection(jdbcUrl, user, password);
             PreparedStatement pstmt = conn.prepareStatement(insertSql)) {
            // 1. For a MySQL DATE column, use Java's LocalDate
            pstmt.setString(1, "Java LocalDate Demo");
            pstmt.setObject(2, LocalDate.now()); // setObject is flexible
            // 2. For a MySQL DATETIME column, use Java's LocalDateTime
            pstmt.setObject(3, LocalDateTime.now());
            // 3. For a MySQL TIMESTAMP column, use Java's ZonedDateTime
            // The driver will convert this to UTC for storage.
            ZonedDateTime nowInMyZone = ZonedDateTime.now(ZoneId.of("America/New_York"));
            pstmt.setObject(4, nowInMyZone); // setObject handles ZonedDateTime -> Timestamp
            int rowsAffected = pstmt.executeUpdate();
            System.out.println(rowsAffected + " row(s) inserted successfully.");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

How to Get Data (MySQL -> Java)

You use ResultSet.getObject() or ResultSet.getTimestamp().

import java.sql.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class MysqlJavaDateSelect {
    public static void main(String[] args) {
        String jdbcUrl = "jdbc:mysql://localhost:3306/your_database";
        String user = "your_user";
        java.sql.Date sqlDate = null;
        java.sql.Timestamp sqlTimestamp = null;
        String selectSql = "SELECT event_date, event_datetime, event_timestamp FROM events WHERE event_name = ?";
        try (Connection conn = DriverManager.getConnection(jdbcUrl, user, password);
             PreparedStatement pstmt = conn.prepareStatement(selectSql)) {
            pstmt.setString(1, "Java LocalDate Demo");
            ResultSet rs = pstmt.executeQuery();
            if (rs.next()) {
                // 1. For a MySQL DATE column, get as Java's LocalDate
                LocalDate localDate = rs.getObject("event_date", LocalDate.class);
                System.out.println("Retrieved LocalDate: " + localDate);
                // 2. For a MySQL DATETIME column, get as Java's LocalDateTime
                LocalDateTime localDateTime = rs.getObject("event_datetime", LocalDateTime.class);
                System.out.println("Retrieved LocalDateTime: " + localDateTime);
                // 3. For a MySQL TIMESTAMP column, get as Java's ZonedDateTime
                // The driver converts the stored UTC back to the JVM's default time zone.
                // It's better to be explicit about the time zone.
                Timestamp ts = rs.getTimestamp("event_timestamp");
                ZonedDateTime zonedDateTime = ts.toLocalDateTime().atZone(ZoneId.systemDefault());
                System.out.println("Retrieved ZonedDateTime (system default): " + zonedDateTime);
                // More robust way to get ZonedDateTime with a specific zone
                ZonedDateTime zonedDateTimeInNY = ts.toLocalDateTime().atZone(ZoneId.of("America/New_York"));
                System.out.println("Retrieved ZonedDateTime (NY): " + zonedDateTimeInNY);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

The Legacy Approach (Not Recommended for New Code)

You might encounter older code using java.util.Date and java.sql.Date. It's important to understand how they work.

MySQL与Java日期如何正确转换?-图3
(图片来源网络,侵删)
Java Type (java.sql) MySQL Type Description & Pitfalls
java.sql.Date DATE Represents a date only. It's a thin wrapper around java.util.Date but with time components set to zero. Pitfall: java.sql.Date is poorly designed and part of the legacy java.sql package.
java.sql.Timestamp DATETIME or TIMESTAMP Represents a point in time with nanosecond precision. This is the most common legacy type for storing both date and time. Pitfall: It also inherits from the problematic java.util.Date.

How to Set Data (Legacy)

import java.sql.*;
import java.util.Date;
public class MysqlJavaDateLegacyInsert {
    public static void main(String[] args) {
        String jdbcUrl = "jdbc:mysql://localhost:3306/your_database";
        String user = "your_user";
        String password = "your_password";
        String insertSql = "INSERT INTO legacy_events (legacy_date, legacy_timestamp) VALUES (?, ?)";
        try (Connection conn = DriverManager.getConnection(jdbcUrl, user, password);
             PreparedStatement pstmt = conn.prepareStatement(insertSql)) {
            // For a DATE column
            java.sql.Date sqlDate = new java.sql.Date(new Date().getTime()); // Wrap java.util.Date
            pstmt.setDate(1, sqlDate);
            // For a DATETIME/TIMESTAMP column
            java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(new Date().getTime());
            pstmt.setTimestamp(2, sqlTimestamp);
            int rowsAffected = pstmt.executeUpdate();
            System.out.println(rowsAffected + " legacy row(s) inserted.");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

How to Get Data (Legacy)

import java.sql.*;
import java.text.SimpleDateFormat;
public class MysqlJavaDateLegacySelect {
    public static void main(String[] args) {
        String jdbcUrl = "jdbc:mysql://localhost:3306/your_database";
        String user = "your_user";
        String password = "your_password";
        String selectSql = "SELECT legacy_date, legacy_timestamp FROM legacy_events";
        try (Connection conn = DriverManager.getConnection(jdbcUrl, user, password);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(selectSql)) {
            if (rs.next()) {
                // Get a DATE
                java.sql.Date sqlDate = rs.getDate("legacy_date");
                System.out.println("Retrieved java.sql.Date: " + sqlDate);
                System.out.println("Formatted java.sql.Date: " + new SimpleDateFormat("yyyy-MM-dd").format(sqlDate));
                // Get a TIMESTAMP
                java.sql.Timestamp sqlTimestamp = rs.getTimestamp("legacy_timestamp");
                System.out.println("Retrieved java.sql.Timestamp: " + sqlTimestamp);
                System.out.println("Formatted java.sql.Timestamp: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(sqlTimestamp));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Summary and Best Practices

Task Modern Java 8+ (java.time) Legacy (java.sql)
Store a Date (no time) LocalDate java.sql.Date
Store a Date & Time (no zone) LocalDateTime java.sql.Timestamp
Store a Date & Time (with zone) ZonedDateTime java.sql.Timestamp (store as UTC, manage zone in app)
Set in PreparedStatement pstmt.setObject(1, myLocalDate); pstmt.setDate(1, mySqlDate);
Get from ResultSet LocalDate date = rs.getObject("my_date", LocalDate.class); java.sql.Date date = rs.getDate("my_date");
Conversion (Legacy -> Modern) LocalDate.from(mySqlDate.toLocalDate()) N/A
Conversion (Modern -> Legacy) java.sql.Date.valueOf(myLocalDate) N/A

Final Recommendation

  1. For all new projects, use java.time objects (LocalDate, LocalDateTime, ZonedDateTime).
  2. Always use PreparedStatement and ResultSet.getObject() or the specific set/get methods. Never use string manipulation.
  3. Choose the right MySQL type:
    • DATE for LocalDate.
    • DATETIME for LocalDateTime.
    • TIMESTAMP for ZonedDateTime if you need time zone awareness and UTC storage.
  4. Avoid java.util.Date and java.sql.Date/Timestamp in your application logic. They are legacy artifacts and their APIs are confusing and error-prone. Use them only as a necessary bridge when interfacing with older systems or libraries that require them.
分享:
扫描分享到社交APP
上一篇
下一篇