在爪哇的奇怪约会

发布于 2024-12-29 15:57:41 字数 705 浏览 0 评论 0原文

以下 Java 代码仅使用 SimpleDateFormat 解析日期(带有时间部分)2009-01-28-09:11:12。我们来看看吧。

final public class Main
{
    public static void main(String[] args)
    {            
        try
        {
            DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
            Date d = df.parse("2009-01-28-09:11:12");
            System.out.println(d);
        }
        catch (ParseException ex)
        {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

上述代码(解析后)显示的日期(带时间)如下。

Sun Nov 30 22:07:51 IST 2008

即使我们尝试解析日期 2009-01-28-09:11:12, 看起来有些古怪。为什么会这样解析呢?

The following Java code just parses a date (with time portion) 2009-01-28-09:11:12 using SimpleDateFormat. Let's have look at it.

final public class Main
{
    public static void main(String[] args)
    {            
        try
        {
            DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
            Date d = df.parse("2009-01-28-09:11:12");
            System.out.println(d);
        }
        catch (ParseException ex)
        {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

The date (with time) displayed (after parsing) by the above code is as follows,

Sun Nov 30 22:07:51 IST 2008

even though we are attempting to parse the date 2009-01-28-09:11:12. It looks somewhat wonky. Why does it parse so?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

银河中√捞星星 2025-01-05 15:57:41

您的日期格式不应该是这样的:

DateFormat df = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");

以匹配此格式:

Date d = df.parse("2009-01-28-09:11:12");

至于为什么,按照这个:

解析器实际上将这些视为数字,技巧在于 - 是数字的一部分,代表负数。因此,如果您这样做:

df.parse("2009-01-02-00:00:00")

它会给出:

Mon Dec 01 00:02:00 EST 2008

将 2009 解析为 yyyy,然后将 -0 解析为 MM(这是上个月,因为月份从 1 开始),然后将 1 解析为 dd,等等。

按照 DateFormat 中的解析:

默认情况下,解析是宽松的:如果输入不是该对象的格式方法使用的形式,但仍然可以解析为日期,则解析成功。客户端可以通过调用 setLenient(false) 来坚持严格遵守格式。

我想,如果您有选择的话,如果您喜欢 2009/01/02 12:34:56 等格式,最好使用斜杠而不是破折号。这:

df.parse("2009/01/02-00:00:00")

会抛出异常:

ERROR java.text.ParseException:
Unparseable date: "2009/01/02-00:00:00"

我只能得出结论, / 不被 DateFormat 视为数字除法是一件非常好的事情...

Shouldn't your date format be something like this:

DateFormat df = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");

to match this format:

Date d = df.parse("2009-01-28-09:11:12");

?

As for why, per this:

the parser actually looks at these as numbers, and the trick is that - is a part of a number, representing negative numbers. So if you do:

df.parse("2009-01-02-00:00:00")

it gives:

Mon Dec 01 00:02:00 EST 2008

That parses 2009 as yyyy, then -0 as MM (which is previous month as months start from 1), then 1 as dd, etc.

As per parse in DateFormat:

By default, parsing is lenient: If the input is not in the form used by this object's format method but can still be parsed as a date, then the parse succeeds. Clients may insist on strict adherence to the format by calling setLenient(false).

I guess, if you have an option, it would be better to use slashes instead of dashes, if you like formats like 2009/01/02 12:34:56. This:

df.parse("2009/01/02-00:00:00")

will throw an exception:

ERROR java.text.ParseException:
Unparseable date: "2009/01/02-00:00:00"

I can only conclude it's a very good thing that / is not considered a number division by DateFormat...

扎心 2025-01-05 15:57:41

好吧,您可以定义您实际正在解析的格式...

Well, you could define the format that you actually are parsing...

世态炎凉 2025-01-05 15:57:41

默认情况下以宽松模式解析日期。这意味着如果不是闰年,它会容忍诸如将 2 月 29 日解析为 3 月 1 日之类的错误。您要求它解析的是 2009 年 1 月 28 日,它会尽职尽责地尝试准确地提供您所要求的内容。

要关闭此行为,请调用 format.setLenient(false)。然后,如果您尝试解析不是真实日期的内容,则日期格式将引发异常。

The dates are parsed in lenient mode by default. This means that it's forgiving to errors like parsing feb 29 as mar 1 if it's not a leap year. What you are asking it to parse is the -28th day of the -1st month of 2009, and it dutifully tries to give you exactly what you ask for.

To turn off this behaviour call format.setLenient(false). Then the dateformat will throw an exception if you try to parse something that's not a real date.

長街聽風 2025-01-05 15:57:41

tl;dr

如果您必须为数据使用自定义格式而不是标准格式,请定义与 java.time.format.DateTimeFormatter 匹配的格式化模式,以解析为 java.time.LocalDateTime 对象。

LocalDateTime
.parse ( 
    "2009-01-28-09:11:12" , 
    DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH:mm:ss" ) 
)
.toString()  // Generate text in standard ISO 8601 format. 

2009-01-28T09:11:12

避免遗留类

您正在使用有严重缺陷的遗留类,这些遗留类已被 Java 8+ 的 JSR 310 中定义的现代 java.time 类所取代。

切勿使用 DateCalendarTimestampSimpleDateFormat 等。

java.time

DateTimeFormatter

定义格式模式以匹配您的非标准格式。实例化 DateTimeFormatter 对象。

String input = "2009-01-28-09:11:12" ;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH:mm:ss" ) ;

LocalDateTime

要表示带有当天时间但缺少时区上下文或相对于 UTC 的偏移量的日期,请使用 java.time.LocalDateTime

LocalDateTime ldt = LocalDateTime.parse ( input , formatter );

ISO 8601

ISO 8601 是文本日期时间格式的国际标准。

日期(带时间部分)2009-01-28-09:11:12

不要发明自己的格式,而应使用 ISO 8601。日期的标准格式在日期部分和日期部分之间使用 T时间部分。

2009-01-28T09:11:12

java.time 类在解析/生成文本时默认使用 ISO 8601 格式。

解析:

LocalDateTime ldt = LocalDateTime.parse( "2009-01-28T09:11:12" ) ;

生成:

String output = ldt.toString() ;  // Produces "2009-01-28T09:11:12".

tl;dr

If you must use a custom format for your data rather than a standard format, define a formatting pattern to match with java.time.format.DateTimeFormatter to parse into a java.time.LocalDateTime object.

LocalDateTime
.parse ( 
    "2009-01-28-09:11:12" , 
    DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH:mm:ss" ) 
)
.toString()  // Generate text in standard ISO 8601 format. 

2009-01-28T09:11:12

Avoid legacy classes

You are using terribly-flawed legacy classes that were supplanted by the modern java.time classes defined in JSR 310 for Java 8+.

Never use Date, Calendar, Timestamp, SimpleDateFormat, etc.

java.time

DateTimeFormatter

Define a formatting pattern to match your non-standard format. Instantiate a DateTimeFormatter object.

String input = "2009-01-28-09:11:12" ;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH:mm:ss" ) ;

LocalDateTime

To represent a date with time-of-day but lacking the context of a time zone or offset-from-UTC, use java.time.LocalDateTime.

LocalDateTime ldt = LocalDateTime.parse ( input , formatter );

ISO 8601

ISO 8601 is an international standard of date-time formats in text.

date (with time portion) 2009-01-28-09:11:12

Rather than invent your own format, use ISO 8601. The standard format for your date uses a T between the date portion and the time portion.

2009-01-28T09:11:12

The java.time classes use ISO 8601 formats by default when parsing/generating text.

Parsing:

LocalDateTime ldt = LocalDateTime.parse( "2009-01-28T09:11:12" ) ;

Generating:

String output = ldt.toString() ;  // Produces "2009-01-28T09:11:12".
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文