带有冒号分隔符的时区的 Java SimpleDateFormat?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2375222/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 06:42:06  来源:igfitidea点击:

Java SimpleDateFormat for time zone with a colon separator?

javadateiso8601

提问by Freiheit

I have a date in the following format: 2010-03-01T00:00:00-08:00

我有以下格式的日期: 2010-03-01T00:00:00-08:00

I have thrown the following SimpleDateFormats at it to parse it:

我在它上面抛出了以下 SimpleDateFormats 来解析它:

private static final SimpleDateFormat[] FORMATS = {
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"), //ISO8601 long RFC822 zone
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"), //ISO8601 long long form zone
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"), //ignore timezone
        new SimpleDateFormat("yyyyMMddHHmmssZ"), //ISO8601 short
        new SimpleDateFormat("yyyyMMddHHmm"),
        new SimpleDateFormat("yyyyMMdd"), //birthdate from NIST IHE C32 sample
        new SimpleDateFormat("yyyyMM"),
        new SimpleDateFormat("yyyy") //just the year
    };

I have a convenience method that uses those formats like so:

我有一个使用这些格式的便捷方法,如下所示:

public static Date figureOutTheDamnDate(String wtf) {
    if (wtf == null) {
        return null;
    }
    Date retval = null;
    for (SimpleDateFormat sdf : FORMATS) {
        try {
            sdf.setLenient(false)
            retval = sdf.parse(wtf);
            System.out.println("Date:" + wtf + " hit on pattern:" + sdf.toPattern());
            break;
        } catch (ParseException ex) {
            retval = null;
            continue;
        }
    }

    return retval;
}

It seems to hit on the pattern yyyyMMddHHmmbut returns the date as Thu Dec 03 00:01:00 PST 2009.

它似乎符合模式,yyyyMMddHHmm但将日期返回为Thu Dec 03 00:01:00 PST 2009.

What is the correct pattern to parse this date?

解析此日期的正确模式是什么?

UPDATE: I don't NEED the time zone parsing. I don't anticipate having time sensitive issues moving between zones, but how would I get the "-08:00" zone format to parse????

更新:我不需要时区解析。我不希望在区域之间移动对时间敏感的问题,但是我将如何解析“-08:00”区域格式????

Unit test:

单元测试:

@Test
public void test_date_parser() {
    System.out.println("\ntest_date_parser");
    //month is zero based, are you effing kidding me
    Calendar d = new GregorianCalendar(2000, 3, 6, 13, 00, 00);
    assertEquals(d.getTime(), MyClass.figureOutTheDamnDate("200004061300"));
    assertEquals(new GregorianCalendar(1950, 0, 1).getTime(), MyClass.figureOutTheDamnDate("1950"));
    assertEquals(new GregorianCalendar(1997, 0, 1).getTime(),  MyClass.figureOutTheDamnDate("199701"));
    assertEquals(new GregorianCalendar(2010, 1, 25, 15, 19, 44).getTime(),   MyClass.figureOutTheDamnDate("20100225151944-0800"));

    //my machine happens to be in GMT-0800
    assertEquals(new GregorianCalendar(2010, 1, 15, 13, 15, 00).getTime(),MyClass.figureOutTheDamnDate("2010-02-15T13:15:00-05:00"));
    assertEquals(new GregorianCalendar(2010, 1, 15, 18, 15, 00).getTime(), MyClass.figureOutTheDamnDate("2010-02-15T18:15:00-05:00"));

    assertEquals(new GregorianCalendar(2010, 2, 1).getTime(), MyClass.figureOutTheDamnDate("2010-03-01T00:00:00-08:00"));
    assertEquals(new GregorianCalendar(2010, 2, 1, 17, 0, 0).getTime(), MyClass.figureOutTheDamnDate("2010-03-01T17:00:00-05:00"));
}

Output from unit test:

单元测试的输出:

test_date_parser
Date:200004061300 hit on pattern:yyyyMMddHHmm
Date:1950 hit on pattern:yyyy
Date:199701 hit on pattern:yyyyMM
Date:20100225151944-0800 hit on pattern:yyyyMMddHHmmssZ
Date:2010-02-15T13:15:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-02-15T18:15:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-03-01T00:00:00-08:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-03-01T17:00:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss

采纳答案by BalusC

JodaTime's DateTimeFormatto rescue:

JodaTimeDateTimeFormat救援:

String dateString = "2010-03-01T00:00:00-08:00";
String pattern = "yyyy-MM-dd'T'HH:mm:ssZ";
DateTimeFormatter dtf = DateTimeFormat.forPattern(pattern);
DateTime dateTime = dtf.parseDateTime(dateString);
System.out.println(dateTime); // 2010-03-01T04:00:00.000-04:00

(time and timezone difference in toString()is just because I'm at GMT-4 and didn't set locale explicitly)

(时间和时区差异toString()只是因为我在 GMT-4 并且没有明确设置语言环境)

If you want to end up with java.util.Datejust use DateTime#toDate():

如果你想结束java.util.Date只是使用DateTime#toDate()

Date date = dateTime.toDate();

Wait for JDK7 (JSR-310)JSR-310, the referrence implementation is called ThreeTen(hopefully it will make it into Java 8) if you want a better formatter in the standard Java SE API. The current SimpleDateFormatindeed doesn't eat the colon in the timezone notation.

等待JDK7 ( JSR-310)JSR-310,如果您想在标准 Java SE API 中使用更好的格式化程序,则引用实现称为ThreeTen(希望它能够进入 Java 8)。当前SimpleDateFormat确实不吃时区符号中的冒号。

Update: as per the update, you apparently don't need the timezone. This should work with SimpleDateFormat. Just omit it (the Z) in the pattern.

更新:根据更新,您显然不需要时区。这应该与SimpleDateFormat. 只需Z在模式中省略它 (the )。

String dateString = "2010-03-01T00:00:00-08:00";
String pattern = "yyyy-MM-dd'T'HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
Date date = sdf.parse(dateString);
System.out.println(date); // Mon Mar 01 00:00:00 BOT 2010

(which is correct as per my timezone)

(根据我的时区,这是正确的)

回答by trashgod

Try setLenient(false).

试试setLenient(false)

Addendum: It looks like you're recognizing variously formatted Datestrings. If you have to do entry, you might like looking at this examplethat extends InputVerifier.

附录:看起来您正在识别各种格式的Date字符串。如果您必须进行输入,您可能会喜欢查看这个扩展的示例InputVerifier

回答by acdcjunior

Here's a snippet I used - with plain SimpleDateFormat. Hope somebody else may benefit from it:

这是我使用的一个片段 - 使用普通的SimpleDateFormat. 希望其他人可以从中受益:

public static void main(String[] args) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") {
        public StringBuffer format(Date date, StringBuffer toAppendTo, java.text.FieldPosition pos) {
            StringBuffer toFix = super.format(date, toAppendTo, pos);
            return toFix.insert(toFix.length()-2, ':');
        };
    };
    // Usage:
    System.out.println(dateFormat.format(new Date()));
}

Output:

输出:

- Usual Output.........: 2013-06-14T10:54:07-0200
- This snippet's Output: 2013-06-14T10:54:07-02:00

Or... better, use a simpler, different, pattern:

或者……更好的是,使用更简单、不同的模式:

SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
// Usage:
System.out.println(dateFormat2.format(new Date()));

Output:

输出:

- This pattern's output: 2013-06-14T10:54:07-02:00

See the docs for that.

请参阅文档

回答by Bludwarf

Thanks acdcjuniorfor your solution. Here's a little optimized version for formatting and parsing:

感谢acdcjunior的解决方案。这是一个用于格式化和解析的优化版本:

public static final SimpleDateFormat XML_SDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.FRANCE)
{
    private static final long serialVersionUID = -8275126788734707527L;

    public StringBuffer format(Date date, StringBuffer toAppendTo, java.text.FieldPosition pos)
    {            
        final StringBuffer buf = super.format(date, toAppendTo, pos);
        buf.insert(buf.length() - 2, ':');
        return buf;
    };

    public Date parse(String source) throws java.text.ParseException {
        final int split = source.length() - 2;
        return super.parse(source.substring(0, split - 1) + source.substring(split)); // replace ":" du TimeZone
    };
};

回答by Rustam

Try this, its work for me:

试试这个,它对我有用:

Date date = javax.xml.bind.DatatypeConverter.parseDateTime("2013-06-01T12:45:01+04:00").getTime();

In Java 8:

在 Java 8 中:

OffsetDateTime dt = OffsetDateTime.parse("2010-03-01T00:00:00-08:00");

回答by YouEyeK

if you used the java 7, you could have used the following Date Time Pattern. Seems like this pattern is not supported in the Earlier version of java.

如果您使用 java 7,则可以使用以下日期时间模式。早期版本的java似乎不支持这种模式。

String dateTimeString  = "2010-03-01T00:00:00-08:00";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
Date date = df.parse(dateTimeString);

For More information refer to the SimpleDateFormatdocumentation.

有关更多信息,请参阅SimpleDateFormat文档

回答by Willie Z

If you can use JDK 1.7 or higher, try this:

如果您可以使用 JDK 1.7 或更高版本,请尝试以下操作:

public class DateUtil {
    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");

    public static String format(Date date) {
        return dateFormat.format(date);
    }

    public static Date parse(String dateString) throws AquariusException {
        try {
            return dateFormat.parse(dateString);
        } catch (ParseException e) {
            throw new AquariusException(e);
        }
    }
}

document: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.htmlwhich supports a new Time Zone format "XXX" (e.g. -3:00)

文档:https: //docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html支持新的时区格式“XXX”(例如 -3:00)

While JDK 1.6 only support other formats for Time Zone, which are "z" (e.g. NZST), "zzzz" (e.g. New Zealand Standard Time), "Z" (e.g. +1200), etc.

而 JDK 1.6 仅支持其他时区格式,即“z”(例如 NZST)、“zzzz”(例如新西兰标准时间)、“Z”(例如 +1200)等。

回答by Basil Bourque

tl;dr

tl;博士

OffsetDateTime.parse( "2010-03-01T00:00:00-08:00" )

Details

细节

The answer by BalusCis correct, but now outdated as of Java 8.

BalusC答案是正确的,但从 Java 8 开始已经过时了。

java.time

时间

The java.timeframework is the successor to both Joda-Time library and the old troublesome date-time classes bundled with the earliest versions of Java (java.util.Date/.Calendar & java.text.SimpleDateFormat).

java.time框架的继承者都乔达时库和与Java(java.util.Date/.Calendar&java.text.SimpleDateFormat中)的最早版本捆绑在一起的老麻烦的日期时间类。

ISO 8601

ISO 8601

Your input data string happens to comply with the ISO 8601standard.

您的输入数据字符串恰好符合ISO 8601标准。

The java.time classes use ISO 8601 formats by default when parsing/generating textual representations of date-time values. So no need to define a formatting pattern.

java.time 类在解析/生成日期时间值的文本表示时默认使用 ISO 8601 格式。所以不需要定义格式模式。

OffsetDateTime

OffsetDateTime

The OffsetDateTimeclass represents a moment on the time line adjusted to some particular offset-from-UTC. In your input, the offset is 8 hours behind UTC, commonly used on much of the west coast of North America.

OffsetDateTime类表示调整到某些特定的时间线瞬间偏移从-UTC。在您的输入中,偏移量比 UTC 晚 8 小时,通常用于北美西海岸的大部分地区。

OffsetDateTime odt = OffsetDateTime.parse( "2010-03-01T00:00:00-08:00" );

You seem to want the date-only, in which case use the LocalDateclass. But keep in mind you are discarding data, (a) time-of-day, and (b) the time zone. Really, a date has no meaning without the context of a time zone. For any given moment the date varies around the world. For example, just after midnight in Paris is still “yesterday” in Montréal. So while I suggest sticking with date-time values, you can easily convert to a LocalDateif you insist.

您似乎只想要日期,在这种情况下使用LocalDate该类。但请记住,您正在丢弃数据、(a) 时间和 (b) 时区。确实,如果没有时区的上下文,日期就没有意义。对于任何特定时刻,日期在世界各地都不同。例如,在巴黎午夜过后在蒙特利尔仍然是“昨天”。因此,虽然我建议坚持使用日期时间值,但LocalDate如果您坚持,您可以轻松转换为 a 。

LocalDate localDate = odt.toLocalDate();

Time Zone

时区

If you know the intended time zone, apply it. A time zone is an offset plusthe rules to use for handling anomalies such as Daylight Saving Time (DST). Applying a ZoneIdgets us a ZonedDateTimeobject.

如果您知道预期的时区,请应用它。时区是偏移量加上用于处理夏令时 (DST)等异常的规则。应用 aZoneId给我们一个ZonedDateTime对象。

ZoneId zoneId = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdt = odt.atZoneSameInstant( zoneId );

Generating strings

生成字符串

To generate a string in ISO 8601 format, call toString.

要生成 ISO 8601 格式的字符串,请调用toString.

String output = odt.toString();

If you need strings in other formats, search Stack Overflow for use of the java.util.formatpackage.

如果您需要其他格式的字符串,请搜索 Stack Overflow 以使用java.util.format包。

Converting to java.util.Date

转换为 java.util.Date

Best to avoid java.util.Date, but if you must, you can convert. Call the new methods added to the old classes such as java.util.Date.fromwhere you pass an Instant. An Instantis a moment on the timeline in UTC. We can extract an Instantfrom our OffsetDateTime.

最好避免java.util.Date,但如果必须,您可以转换。调用添加到旧类的新方法,例如在java.util.Date.from何处传递Instant. AnInstantUTC时间线上的一个时刻。我们可以Instant从我们的OffsetDateTime.

java.util.Date utilDate = java.util.Date( odt.toInstant() );


About java.time

关于java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

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

You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*classes.

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

Where to obtain the java.time classes?

从哪里获得 java.time 类?

The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多

回答by Abhishek Oza

Since an example of Apache FastDateFormat(click for the documentations of versions:2.6and3.5) is missing here, I am adding one for those who may need it. The key here is the pattern ZZ(2 capital Zs).

由于此处缺少Apache FastDateFormat 示例(单击以获取版本的文档:2.63.5),因此我为可能需要它的人添加了一个示例。这里的关键是模式ZZ(2个大写Z)。

import java.text.ParseException
import java.util.Date;
import org.apache.commons.lang3.time.FastDateFormat;
public class DateFormatTest throws ParseException {
    public static void main(String[] args) {
        String stringDateFormat = "yyyy-MM-dd'T'HH:mm:ssZZ";
        FastDateFormat fastDateFormat = FastDateFormat.getInstance(stringDateFormat);
        System.out.println("Date formatted into String:");
        System.out.println(fastDateFormat.format(new Date()));
        String stringFormattedDate = "2016-11-22T14:30:14+05:30";
        System.out.println("String parsed into Date:");
        System.out.println(fastDateFormat.parse(stringFormattedDate));
    }
}

Here is the output of the code:

这是代码的输出:

Date formatted into String:
2016-11-22T14:52:17+05:30
String parsed into Date:
Tue Nov 22 14:30:14 IST 2016

Note: The above code is of Apache Commons' lang3. The class org.apache.commons.lang.time.FastDateFormatdoes not support parsing, and it supports only formatting. For example, the output of the following code:

注意:以上代码来自 Apache Commons 的 lang3。该类org.apache.commons.lang.time.FastDateFormat不支持解析,只支持格式化。例如,以下代码的输出:

import java.text.ParseException;
import java.util.Date;
import org.apache.commons.lang.time.FastDateFormat;
public class DateFormatTest {
    public static void main(String[] args) throws ParseException {
        String stringDateFormat = "yyyy-MM-dd'T'HH:mm:ssZZ";
        FastDateFormat fastDateFormat = FastDateFormat.getInstance(stringDateFormat);
        System.out.println("Date formatted into String:");
        System.out.println(fastDateFormat.format(new Date()));
        String stringFormattedDate = "2016-11-22T14:30:14+05:30";
        System.out.println("String parsed into Date:");
        System.out.println(fastDateFormat.parseObject(stringFormattedDate));
    }
}

will be this:

将是这样的:

Date formatted into String:
2016-11-22T14:55:56+05:30
String parsed into Date:
Exception in thread "main" java.text.ParseException: Format.parseObject(String) failed
    at java.text.Format.parseObject(Format.java:228)
    at DateFormatTest.main(DateFormatTest.java:12)

回答by bigspawn

You can use X in Java 7.

您可以在 Java 7 中使用 X。

https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

static final SimpleDateFormat DATE_TIME_FORMAT = 
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

static final SimpleDateFormat JSON_DATE_TIME_FORMAT = 
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");

private String stringDate = "2016-12-01 22:05:30";
private String requiredDate = "2016-12-01T22:05:30+03:00";

@Test
public void parseDateToBinBankFormat() throws ParseException {
    Date date = DATE_TIME_FORMAT.parse(stringDate);
    String jsonDate = JSON_DATE_TIME_FORMAT.format(date);

    System.out.println(jsonDate);
    Assert.assertEquals(jsonDate, requiredDate);
}