Java DateFormat 和 SimpleDateFormat 返回不正确的日期

问题描述 投票:0回答:3

今天是 2010 年 2 月 9 日星期二,当我打印日期时,我得到了错误的日期:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

Date today = formatter.parse(String.format("%04d-%02d-%02d",
        Calendar.getInstance().get(Calendar.YEAR),
        Calendar.getInstance().get(Calendar.MONTH),
        Calendar.getInstance().get(Calendar.DAY_OF_MONTH)));

System.out.println("Today is " + today.toString());

打印行结果为:“Today is Sat Jan 09 00:00:00 CST 2010”

这肯定不是 1 月 9 日星期六,而是 2 月 9 日星期二。我假设我做错了什么,所以有人可以让我知道这里出了什么问题吗?我必须手动设置星期几吗?

更新 注意:我今天不想用

new Date()
初始化,因为我希望将小时、分钟、秒和毫秒初始化为
0
。 这是必要的,因此我可以将用户输入的日期与今天进行比较:如果用户输入今天的日期并且我使用格式化程序来构造一个 Date 对象,那么如果我使用
new Date()
初始化今天并比较这两个日期 - 今天将是在用户选择的日期之后(这是不正确的)。 因此,我需要在今天开始时初始化,没有小时/分钟/秒/毫秒。

java date date-format simpledateformat
3个回答
9
投票

令人困惑的是,日历月份从 0(一月)到 11(十二月)计数,因此当您从日历中提取 MONTH 字段时,您将“2010-01-09”传递给 formatter.parse()。

在相关的SO问题中对此进行了讨论。


3
投票

如果您不想使用 JodaTime 您可以使用:

Calendar calendar = Calendar.getInstance();

calendar.set( Calendar.HOUR_OF_DAY, 0 );
calendar.set( Calendar.MINUTE, 0 );
calendar.set( Calendar.SECOND, 0 );
calendar.set( Calendar.MILLISECOND, 0 );

Date today = calendar.getTime();

这比字符串格式化/解析方法更高效且更不易出错。

如果您可以使用 JodaTime,这是一个更优选的方法:

LocalDate date = new DateTime().toLocaleDate();

0
投票

java.time

2014 年 3 月,Java 8 引入了现代的

java.time
日期时间 API,取代了容易出错的旧版
java.util
日期时间 API
。任何新代码都应使用
java.time
API*

另外,下面是Joda-Time主页上的通知:

请注意,从 Java SE 8 开始,用户被要求迁移到

java.time
(JSR-310) - JDK 的核心部分,它取代了这个 项目。

使用现代日期时间 API 的解决方案

您提到过:

我今天不想用

new Date()
初始化,因为我想要 小时、分钟、秒和毫秒初始化为 0。这是 必要的,这样我就可以将用户输入的日期与今天进行比较

您可以使用

LocalDate#now
获取今天的日期。然后,您可以使用
LocalDate#isAfter
LocalDate#isBefore
LocalDate#isEqual
进行比较。

演示:

import java.time.*;
import java.util.Scanner;

public class Main{
    public static void main(String[] args) {
        // ZoneId.systemDefault() returns the system default time zone.
        // Replace it as per your requirement e.g. ZoneId.of("Europe/London").
        LocalDate today = LocalDate.now(ZoneId.systemDefault());

        // Accept user input
        Scanner scanner = new Scanner(System.in);
        System.out.print("Enter year, month and day: ");
        int year = scanner.nextInt();
        int month = scanner.nextInt();
        int day = scanner.nextInt();

        // Create a LocalDate object
        LocalDate inputDate = LocalDate.of(year, month, day);

        // Print and compare
        System.out.println("Input date: " + inputDate);
        System.out.println("Today's date: " + today);
        if (inputDate.isAfter(today)) {
            System.out.println("Input date is after today's date.");
        } else if (inputDate.isBefore(today)) {
            System.out.println("Input date is before today's date.");
        } else {
            System.out.println("Input date is today's date.");
        }
    }
}

示例运行:

Enter year, month and day: 2024 4 30
Input date: 2024-04-30
Today's date: 2024-10-21
Input date is before today's date.

尽管您已经提到,“我希望将小时、分钟、秒和毫秒初始化为 0”,但您的用例并不要求您获取时间组件初始化为 0 的日期时间对象。但是,如果您'你很好奇如何获得这样一个日期时间对象,

java.time
API 让你变得非常方便:

// ZoneId.systemDefault() returns the system default time zone.
// Replace it as per your requirement e.g. ZoneId.of("Europe/London").
ZoneId defaultZoneId = ZoneId.systemDefault();
ZonedDateTime today = LocalDate.now(defaultZoneId).atStartOfDay(defaultZoneId);

奖金

如果您想将日期和时间与时区进行比较,可以使用

ZonedDateTime

演示:

import java.time.*;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        // ZoneId.systemDefault() returns the system default time zone.
        // Replace it as per your requirement e.g. ZoneId.of("Europe/London").
        ZonedDateTime now = ZonedDateTime.now(ZoneId.systemDefault());

        // Accept user input
        Scanner scanner = new Scanner(System.in);
        System.out.print("Enter date in the format yyyy-MM-dd: ");
        LocalDate date = LocalDate.parse(scanner.nextLine());
        System.out.print("Enter time in the format HH:mm:ss: ");
        LocalTime time = LocalTime.parse(scanner.nextLine());
        System.out.print("Enter time zone e.g. Asia/Kolkata: ");
        ZoneId zoneId = ZoneId.of(scanner.nextLine());

        // Convert user input into ZonedDateTime
        ZonedDateTime zdt = ZonedDateTime.of(date, time, zoneId);

        // Print now and the ZonedDateTime initialised with user input
        System.out.printf("Now: %s = %s at UTC%n", now.toString(), now.toInstant());
        System.out.printf("Input date-time: %s = %s at UTC%n", zdt.toString(), zdt.toInstant());

        // Compare now with user provided date time with time zone information
        if (now.isBefore(zdt)) {
            System.out.println("The input date-time is in the future.");
        } else if (now.isAfter(zdt)) {
            System.out.println("The input date-time is in the past.");
        } else {
            System.out.println("The input date-time is the current time.");
        }
    }
}

在我的欧洲/伦敦时区运行的示例:

Enter date in the format yyyy-MM-dd: 2024-10-21
Enter time in the format HH:mm:ss: 20:30:40
Enter time zone e.g. Asia/Kolkata: Asia/Kolkata
Now: 2024-10-21T20:45:22.775388700+01:00[Europe/London] = 2024-10-21T19:45:22.775388700Z at UTC
Input date-time: 2024-10-21T20:30:40+05:30[Asia/Kolkata] = 2024-10-21T15:00:40Z at UTC
The input date-time is in the past.

注意: 我更改了此演示中的输入样式,以展示

LocalDate
LocalTime
在不使用 DateTimeFormatter 的情况下解析
ISO 8601
格式的输入的能力。检查
LocalDate#parse
LocalTime#parse
了解更多信息。

Trail:日期时间了解有关现代日期时间 API 的更多信息。


* 如果您收到

java.util.Date
的实例,请使用
java.time.Instant
 将其转换为 
Date#toInstant
,并根据您的要求从中派生
java.time
的其他日期时间类。

© www.soinside.com 2019 - 2024. All rights reserved.