【问题标题】:How to get correct date from a string in Java using SimpleDateFormat?如何使用 SimpleDateFormat 从 Java 中的字符串中获取正确的日期?
【发布时间】:2019-05-16 22:00:59
【问题描述】:

我正在编写一个应用程序,并且必须将字符串转换为日期。该字符串将包含周、天等信息,并最终计算从该日期到当前时间的时间差(以分钟为单位),如下所示。使用我拥有的代码,我希望将“过去”对象作为某个日历日期,即从当前时间开始的“13 周、2 天、16 小时、42 分钟”,但我发现让我感到惊讶(日期对象是 Tue Mar 24 15:54:00 CST 1970 截至目前)。有人可以解释一下为什么我的代码不起作用以及如何解决这个问题吗?我提到了Java Docs,但对我没有多大帮助。

        String givenStr = "13 weeks, 2 days, 16 hours, 42 minutes";
        SimpleDateFormat format = new SimpleDateFormat("w 'weeks', u 'days', H 'hours', m 'minutes'");
        try {
            Date past =  format.parse(givenStr);
            Date now = new Date();
            Long minutes = (now.getTime()-past.getTime())/(60*1000);
            System.out.printf("Date: %s Minutes: %s\n", past, minutes);
        } catch (ParseException ex) {
            //DO STH
        }

【问题讨论】:

  • 日期不是持续时间。
  • 我建议你不要使用SimpleDateFormatDate。这些类设计不良且过时,尤其是前者,尤其是出了名的麻烦。而是使用来自java.time, the modern Java date and time API 的类。
  • 您的字符串是否总是正好包含这四个单位(周、天、小时、分钟)?计数为 1 时是否也使用复数形式 (1 weeks, 1 days, 0 hours, 1 minutes)?

标签: java datetime simpledateformat


【解决方案1】:

tl;博士

使用standard ISO 8601 formatting 作为您的时间跨度文本:P13W2DT16H42M

使用 java.time 框架和 ThreeTen-Extra 库中的现代日期时间类:InstantPeriodDurationDuration .

Instant
.now()
.plus(
    PeriodDuration
    .parse(
        "P" + 
        "13 weeks, 2 days, 16 hours, 42 minutes"
        .replace( " weeks, " , "W" )
        .replace( " days, " , "DT" )
        .replace( " hours, " , "H" )
        .replace( " minutes" , "M" )
    )
)

2019-08-18T18:30:42.007034Z

详情

您将两个不同的概念混为一谈:

  • 时刻,时间轴上的一个点
  • 一个时间跨度未附加到时间线

时刻

暂时,我们不再使用java.util.Date 类。那个可怕的类在几年前被java.time.Instant 类所取代。

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

时间跨度

你的输入字符串代表片刻。它代表一个时间跨度。

对于年-月-日的跨度,我们使用Period 类。对于以小时-分钟-秒为单位的跨度,我们使用Duration

PeriodDuration

您可以使用从ThreeTen-Extra 项目构建的外部库中的PeriodDuration 类来组合这两个概念。但是你应该三思而后行。将这两种粒度结合起来几乎没有实际意义。

但是,如果你坚持,让我们试一试。

首先,更改您的输入字符串以使用标准ISO 8601 formatPnYnMnDTnHnMnS。在这种格式中,P 标志着开始,T 将粗粒度与细粒度分开。

String input = "P" + "13 weeks, 2 days, 16 hours, 42 minutes".replace( " weeks, " , "W" ).replace( " days, " , "DT" ).replace( " hours, " , "H" ).replace( " minutes" , "M" ) ;

P13W2DT16H42M

将新输入解析为PeriodDuration

PeriodDuration pd = PeriodDuration.parse( input );

以 UTC 捕捉当前时刻。

Instant now = Instant.now();

now.toString(): 2019-05-17T01:48:42.007034Z

添加您的时间段以确定未来的时刻。

Instant later = now.plus( pd );

later.toString(); 2019-08-18T18:30:42.007034Z

如果您想要过去的时刻而不是未来的时刻,请致电Instant::minus

Instant earlier = now.minus( pd ) ;

经过的分钟数

如果您想要这两个时刻之间经过的总分钟数,请使用Duration 类。

Duration d = Duration.between( now , later ) ;
long minutesTotal = d.toMinutes() ;

分钟总数:134922

时区

如果您想处理特定地区(时区)人们使用的挂钟时间感知的时刻,请使用 ZonedDateTimeZoneId 类。调用同名的plus/minus 方法,如上所示。

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;
ZoneDateTime earlier = now.minus( pd ) ;

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 1970-01-01
    • 2020-06-09
    • 1970-01-01
    • 2012-05-23
    • 2014-10-14
    相关资源
    最近更新 更多