在 Java 中将字符串转换为日历对象

Posted

技术标签:

【中文标题】在 Java 中将字符串转换为日历对象【英文标题】:Convert String to Calendar Object in Java 【发布时间】:2011-07-15 03:31:00 【问题描述】:

我是 Java 新手,通常使用 php

我正在尝试转换这个字符串:

2011 年 3 月 14 日星期一 16:02:37 GMT

到一个日历对象中,这样我就可以像这样轻松地提取年份和月份:

String yearAndMonth = cal.get(Calendar.YEAR)+cal.get(Calendar.MONTH);

手动解析会是个坏主意吗?使用子字符串方法?

任何建议都会有所帮助,谢谢!

【问题讨论】:

How to convert a date String to a Date or Calendar object?的可能重复 【参考方案1】:
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
cal.setTime(sdf.parse("Mon Mar 14 16:02:37 GMT 2011"));// all done

注意:根据您的环境/要求设置Locale


另见

Javadoc

【讨论】:

onlineconversion.com/unix_time.htm。这是在线时间戳转换器。由java代码计算的值和这个在线转换得到的值不同。为什么??你能通过这个吗?谢谢:) 请注意,这会丢失时区信息。 Calendar 对象将具有系统默认的 TimeZone 而不是解析的。 这不再是最热门/被接受的答案了。由于 Java 8 已经推出超过 4 年,因此应更新答案以提及 java.time。这个问答在谷歌上非常突出。【参考方案2】:

tl;博士

现代方法使用 java.time 类。

YearMonth.from(
    ZonedDateTime.parse( 
        "Mon Mar 14 16:02:37 GMT 2011" , 
        DateTimeFormatter.ofPattern( "E MMM d HH:mm:ss z uuuu" )
     )
).toString()

2011-03

避免使用旧的日期时间类

现代方法是使用 java.time 类。旧的日期时间类(例如 Calendar)已被证明设计不佳、令人困惑且麻烦。

定义一个自定义格式化程序以匹配您的字符串输入。

String input = "Mon Mar 14 16:02:37 GMT 2011";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "E MMM d HH:mm:ss z uuuu" );

解析为ZonedDateTime

ZonedDateTime zdt = ZonedDateTime.parse( input , f );

您对年份和月份感兴趣。为此目的,java.time 类包括 YearMonth 类。

YearMonth ym = YearMonth.from( zdt );

如果需要,您可以查询年份和月份数字。

int year = ym.getYear();
int month = ym.getMonthValue();

toString 方法会生成标准ISO 8601 格式的字符串。

String output = ym.toString();

把这些放在一起。

String input = "Mon Mar 14 16:02:37 GMT 2011";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "E MMM d HH:mm:ss z uuuu" );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
YearMonth ym = YearMonth.from( zdt );
int year = ym.getYear();
int month = ym.getMonthValue();

转储到控制台。

System.out.println( "input: " + input );
System.out.println( "zdt: " + zdt );
System.out.println( "ym: " + ym );

输入:2011 年 3 月 14 日星期一 16:02:37 GMT

zdt: 2011-03-14T16:02:37Z[GMT]

名称:2011-03

实时代码

见this code running in IdeOne.com。

转化

如果您必须有一个Calendar 对象,您可以使用添加到旧类的新方法转换为GregorianCalendar

GregorianCalendar gc = GregorianCalendar.from( zdt );

关于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.* 类。 Hibernate 5 & JPA 2.2 支持 java.time

从哪里获取 java.time 类?

Java SE 8Java SE 9Java SE 10Java SE 11 和更高版本 - 具有捆绑实现的标准 Java API 的一部分。 Java 9 带来了一些小功能和修复。 Java SE 6Java SE 7 大部分 java.time 功能在ThreeTen-Backport 中向后移植到 Java 6 和 7。 Android java.time 类的更高版本的 android (26+) 捆绑实现。 对于早期的 Android (API desugaring 的进程带来了最初未内置于 Android 中的subset of the java.time 功能。 如果脱糖无法满足您的需求,ThreeTenABP 项目会将ThreeTen-Backport(如上所述)适配到 Android。见How to use ThreeTenABP…

【讨论】:

【参考方案3】:

好吧,我认为复制 SimpleDateFormat 等类中已经存在的代码是个坏主意。

另一方面,我个人建议尽可能避免使用CalendarDate,而是使用Joda Time 作为设计更好的日期和时间API。例如,您需要注意SimpleDateFormat不是线程安全的,因此每次使用它时都需要线程本地、同步或新实例。 Joda 解析器和格式化程序线程安全的。

【讨论】:

感谢您的意见,我以后一定会考虑使用 Joda,看起来很有用 @Jon Skeet Joda 不会在 Android 中反序列化。除非您不需要保存日期和时间,否则 Joda 的价值不大。 @FrankZappa:我不同意这一点 - 您可以在 Joda Time 中进行所有日期/时间计算,然后转换为其他类型(为简单起见可能只是字符串) 用于序列化目的。 抱歉,不得不投反对票,答案太老了,排名最高的答案已经过时。今天java.time 是要走的路,Basil Bourque 提供了一个很好的答案。 @Scolytus:最高(并被接受)的答案有 332 票,而这个答案有 10 票。我认为,如果您对现在有更好解决方案的每个 7 岁以上的答案进行投票,那么您将用完投票……(我同意巴兹尔的回答很好,我对此表示赞成。) 【参考方案4】:

不需要创建新的日历,SimpleDateFormat 已经在下面使用了一个日历。

SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.EN_US);
Date date = sdf.parse("Mon Mar 14 16:02:37 GMT 2011"));// all done
Calendar cal = sdf.getCalendar();

(我还不能发表评论,这就是我创建新答案的原因)

【讨论】:

您的解决方案看起来很优雅,但有两个缺点: 1. JavaDoc 不保证行为符合预期。 2. 至少对于 Java 6,您可以在第 1353 行找到克隆日历对象的路径。那么 !date.equals(cal.getTime()).【参考方案5】:

SimpleDateFormat 很棒,请注意HHhh 在工作时间时不同。 HH 将返回 24 小时制,hh 将返回 12 小时制。

例如,以下将返回 12 小时时间:

SimpleDateFormat sdf = new SimpleDateFormat("hh:mm aa");

虽然这将返回 24 小时时间:

SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");

【讨论】:

【参考方案6】:

使用时区解析时间,Z 模式中是时区

String aTime = "2017-10-25T11:39:00+09:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
try 
    Calendar cal = Calendar.getInstance();
    cal.setTime(sdf.parse(aTime));
    Log.i(TAG, "time = " + cal.getTimeInMillis()); 
 catch (ParseException e) 
    e.printStackTrace();

输出:它将返回UTC时间

1508899140000

如果我们没有像yyyy-MM-dd'T'HH:mm:ss 这样的模式设置时区。 SimpleDateFormat 将使用Setting 中设置的时区

【讨论】:

【参考方案7】:

是的,自己解析是不好的做法。看看SimpleDateFormat,它会把String变成Date,你可以把Date设置成Calendar实例。

【讨论】:

【参考方案8】:

简单方法:

public Calendar stringToCalendar(String date, String pattern) throws ParseException 
    String DEFAULT_LOCALE_NAME = "pt";
    String DEFAULT_COUNTRY = "BR";
    Locale DEFAULT_LOCALE = new Locale(DEFAULT_LOCALE_NAME, DEFAULT_COUNTRY);
    SimpleDateFormat format = new SimpleDateFormat(pattern, LocaleUtils.DEFAULT_LOCALE);
    Date d = format.parse(date);
    Calendar c = getCalendar();
    c.setTime(d);
    return c;

【讨论】:

以上是关于在 Java 中将字符串转换为日历对象的主要内容,如果未能解决你的问题,请参考以下文章

在java中将布尔对象转换为字符串的最佳方法

在 Java ME 中将 JSON 字符串转换为对象?

在Java中将字符串转换为“字符”数组

在C#中将对象转换为JSON字符串[重复]

在 PHP 中将对象转换为 JSON 并将 JSON 转换为对象,(像 Gson for Java 之类的库)

在Jackson中将Java对象转换为JsonNode [重复]