如何将格式为(Tue Jul 13 00:00:00 CEST 2010)的日期转换为Java日期(该字符串来自Alfresco属性)

24
我正在管理一个来自Alfresco属性的日期,格式为(Tue Jul 13 00:00:00 CEST 2010),我需要将其转换为Java日期... 我已经找了很多关于各种字符串转日期的帖子,也看了这个页面,所以我尝试了以下代码:
private static final DateFormat alfrescoDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
Date dataRispostaDate = alfrescoDateFormat.parse(dataRisposta);

但它抛出了一个异常。(该异常是(SSollevata un'eccezione durante la gestione della data: java.text.ParseException: Unparseable date: "Tue Jul 13 00:00:00 CEST 2011").

我发布完整的代码:

        try {
            QName currDocTypeQName = (QName) nodeService.getType(doc);
            log.error("QName:["+currDocTypeQName.toString()+"]");
            if (currDocTypeQName != null) {
                String codAtto = AlfrescoConstants.getCodAttoFromQName(currDocTypeQName.toString());
                log.error("codAtto:["+codAtto+"]");
                if (codAtto.equals(AlfrescoConstants.COD_IQT)){
                    List<ChildAssociationRef> risposteAssociate = nodeService.getChildAssocs(doc, AlfrescoConstants.QN_RISPOSTEASSOCIATE, RegexQNamePattern.MATCH_ALL);
                    for (ChildAssociationRef childAssocRef : risposteAssociate) {
                        // Vado a prendere il nodo
                        NodeRef risposta = childAssocRef.getChildRef();
                        String dataRisposta = (nodeService.getProperty(risposta, AlfrescoConstants.QN_DATA_RISPOSTA)).toString();
                        log.error("dataRisposta:["+dataRisposta+"]");
                        if (!dataRisposta.isEmpty()){
                            try {
                                Date dataDa = dmyFormat.parse(req.getParameter("dataDa"));
                                log.error("dataDa:["+dataDa.toString()+"]");
                                Date dataA = dmyFormat.parse(req.getParameter("dataA"));
                                log.error("dataA:["+dataA.toString()+"]");
                                Date dataRispostaDate = alfrescoDateFormat.parse(dataRisposta);
                                log.error("dataRispostaDate:["+dataRispostaDate.toString()+"]");

                                if (dataRispostaDate.after(dataDa) && dataRispostaDate.before(dataA)){
                                    results.add(doc);
                                    log.error("La data risposta  è compresa tra le date specificate");
                                }else{
                                    log.error("La data risposta non è compresa tra le date specificate");
                                }
                            } catch (ParseException e) {
                                log.error("Sollevata un'eccezione durante la gestione della data: " + e);
                                throw new RuntimeException("Formato data non valido");
                            }
                        }else{
                            log.error("La data risposta non è specificata");
                        }
                    }
                }else{
                    results.add(doc);
                }
            }
        } catch (Exception e) {
            log.error("Sollevata un'eccezione durante la gestione del codice atto nel webscript nicola: " + e);
        }

有人可以帮忙吗?


1
你能详细说明一下“它不起作用”是什么意思吗?具体出现了什么问题? - Jon Skeet
1
@Nicola 假设"log"是log4j或java.util.logging,请将catch块中的代码行更改为:log.error("在处理nicola网页脚本时引发异常,e); - Sean Reilly
1
定义如下: <property name="crl:data_risposta"> <title>Data risposta</title> <type>d:date</type> </property> 你是说这应该可以工作吗? Date dataRisposta = (Date)(nodeService.getProperty(risposta, AlfrescoConstants.QN_DATA_RISPOSTA)); - Nicola Peluchetti
1
@Gagravarr 你说得对,它有效!如果你回答这个帖子,我会把你的答案标记为被接受的。 - Nicola Peluchetti
1
请注意,旧的日期时间类(如 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat)现在已被认为是遗留系统,Java 8 和 Java 9 中的 java.time 类取代了它们。请参见 Oracle 的教程 - Basil Bourque
显示剩余9条评论
5个回答

32

基本上你的问题是你正在使用一个SimpleDateFormat(String pattern)构造函数,而javadoc中说:

使用给定的模式和默认日期格式符号以及默认语言环境构造SimpleDateFormat。

如果你尝试使用以下代码:

DateFormat osLocalizedDateFormat = new SimpleDateFormat("MMMM EEEE");
System.out.println(osLocalizedDateFormat.format(new Date()))

你会注意到,它根据你的语言环境打印出月份和星期几的标题。
解决你的问题的方法是使用SimpleDateFormat(String pattern, Locale locale)构造函数覆盖默认的日期语言环境。
DateFormat dateFormat = new SimpleDateFormat(
            "EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
dateFormat.parse("Tue Jul 13 00:00:00 CEST 2011");
System.out.println(dateFormat.format(new Date()));

这很有道理。@Nicola,你的默认语言环境是意大利语吗? - Sean Reilly
是的,我认为这是一个非常好的建议。我已经将另一个标记为答案,因为我的问题与"Alfresco相关",而另一个答案在我的情况下更加简洁,但还是感谢你的回答! - Nicola Peluchetti
请注意,旧的日期时间类(如java.util.Datejava.util.Calendarjava.text.SimpleDateFormat)现在已经成为遗留系统,被内置于Java 8和Java 9中的java.time类所取代。请参阅Oracle的教程 - Basil Bourque
不知道这段代码出了什么问题,我只是想让我的输入日期2019/05/05保存在数据库中,但是当运行时,解析日期的结果却是"Tue Jul 13 00:00:00 CEST 2011"这样的格式,而实际上应该保存的是2019/05/05。我很困惑为什么我知道应该保存的值与实际保存在数据库中的值不同,或者是否有一些隐藏的过程正在进行?无论如何,现在我的日期解析正确了,太好了。谢谢。 - iamjoshua

7

简而言之

ZonedDateTime.parse(                     // Produce a `java.time.ZonedDateTime` object.
    "Wed Jul 13 00:00:00 CEST 2011" ,    // Corrected `Tue` to `Wed`.
    DateTimeFormatter.ofPattern( "EEE MMM d HH:mm:ss zzz uuuu" , Locale.US  ) 
)

2011-07-13T00:00+02:00[欧洲/巴黎]

数据错误:WedTue

您输入的字符串Tue Jul 13 00:00:00 CEST 2011是无效的。2011年7月13日是星期三,不是星期二

String input = "Wed Jul 13 00:00:00 CEST 2011" ;  // Corrected `Tue` to `Wed`.

java.time

现代方法使用java.time类而不是其他答案中看到的麻烦的旧遗留日期时间类。

定义一个格式化模式来匹配您的输入字符串。请注意Locale,该语言定义用于解析月份名称和星期几名称的人类语言。

Duck Duck Go搜索引擎中7月份日历的屏幕截图

DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEE MMM d HH:mm:ss zzz uuuu" , Locale.US  );
ZonedDateTime zdt = ZonedDateTime.parse( input , f  );

zdt.toString(): 2011-07-13T00:00+02:00[Europe/Paris]

时区

CEST 是一个伪时区,不是真正的时区。请不要使用这些伪时区,因为它们没有标准化,甚至不唯一。

ZonedDateTime 类会尝试猜测这种三到四个字符的伪时区的意图。你的 CEST 巧合地被解释为Europe/Paris时区。但你不能保证这种猜测100%成功。相反,要完全避免使用这些伪时区

在格式为大陆/地区正确时区名称中指定时区,例如America/MontrealAfrica/CasablancaPacific/Auckland

ZoneId z = ZoneId.of( "Europe/Paris" );  // https://time.is/Paris
LocalDate today = LocalDate.now( z );  // Current date varies around the globe by zone.

ISO 8601

您输入的日期格式非常糟糕。将日期时间值序列化为文本时,仅使用标准ISO 8601格式。

ZonedDateTime类聪明地通过在方括号中附加时区名称来扩展标准格式,如上面的示例所示。


关于java.time

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

现在进入Joda-Time项目的维护模式,建议迁移到java.time类。

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

在哪里获取java.time类?

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


6

根据您的评论,我相信您的属性实际上是d:dated:datetime类型。如果是这样,该属性将作为Java日期对象从Alfresco返回。因此,您需要做的就是:

  NodeRef risposta = childAssocRef.getChildRef();
  Date dataRisposta = (Date)nodeService.getProperty(risposta, AlfrescoConstants.QN_DATA_RISPOSTA);

2
问题在于CEST不是Java支持的时区。您可以使用“CST”。
TimeZone的Javadoc注释如下:
三字母时区ID 为了与JDK 1.1.x兼容,还支持一些其他三字母时区ID(例如“PST”,“CTT”,“AST”)。然而,它们的使用已经被弃用,因为同一缩写通常用于多个时区(例如,“CST”可能是美国“中央标准时间”和“中国标准时间”),Java平台只能识别其中之一。
对于三/四字母时区支持,建议使用JodaTime,它可能做得更好。
String dataRisposta = "Tue Jul 13 00:00:00 CST 2010";
Date dataRispostaDate = alfrescoDateFormat.parse(dataRisposta);
System.out.println(dataRispostaDate);

输出

Tue Jul 13 07:00:00 BST 2010

String[] ids = TimeZone.getAvailableIDs();
Arrays.sort(ids);
for (String id : ids) {
    System.out.println(id);
}

打印

...
CAT
CET
CNT
CST
CST6CDT
CTT
...

问题在于该字符串是 Alfresco 节点的一个属性。 我使用以下代码获取它: String dataRisposta = (nodeService.getProperty(risposta, AlfrescoConstants.QN_DATA_RISPOSTA)).toString(); - Nicola Peluchetti
@Sean Reilly,我猜你没有完整地阅读我的回答:“CEST不是Oracle Java 6 update 23中支持的时区。它也不会给我报错,只是按本地时区给出时间。” - Peter Lawrey
1
更新没有成功,但使用以下代码行成功了: Date dataRisposta = (Date)(nodeService.getProperty(risposta, AlfrescoConstants.QN_DATA_RISPOSTA)); - Nicola Peluchetti
换句话说,没有必要解析它。这个想法在我脑海中闪过。 ;) - Peter Lawrey
1
FYI,Joda-Time 项目现已进入 维护模式,团队建议迁移到 java.time 类。请参阅 Oracle 的教程 - Basil Bourque
显示剩余11条评论

0

试试这个函数,我之前也遇到了同样的问题。

public String getMyDate(String myDate, String requiredFormat, String mycurrentFormat) {
    DateFormat dateFormat = new SimpleDateFormat(returnFormat);
    Date date = null;
    String returnValue = "";
    try {
        date = new SimpleDateFormat(myFormat, Locale.ENGLISH).parse(myDate);
        returnValue = dateFormat.format(date);
    } catch (ParseException e) {
        returnValue = myDate;
    }
    return returnValue;
}

示例:

2020年5月6日星期三13:01:29 EDT,即“EEE MMM dd HH:mm:ss zzz yyyy”是我的当前格式。

2020年5月4日,即“d.MMM.yyyy”是我需要的格式。

Date date = new Date();

getMyDate(date.toString(), "d.MMM.yyyy", "EEE MMM dd HH:mm:ss zzz yyyy")

请不要教年轻人使用早已过时且臭名昭著的SimpleDateFormat类。至少不要将其作为第一选择。也不要毫无保留地使用它。今天我们有更好的选择,java.time,这是现代Java日期和时间API,以及它的DateTimeFormatter。此外,您的代码比大多数其他答案中的代码都要长。它有什么优势吗? - Ole V.V.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接