将整数YYYYMMDD转换为具有本地时区的java.util.Date的好方法

问题描述 投票:-1回答:4

我了解此问题可能看起来像是FAQ主题,但关键是时区和性能。我有整数YYYYMMDD日期(例如20150131)。这是一个很好的“几乎可以工作”的解决方案:

import org.joda.time.DateTime;
import java.util.Date;

// ...

public Date extract(final int intDate) {
    Date result = null;

    try {
        result = new DateTime(
                intDate / 10000,
                (intDate / 100) % 100,
                intDate % 100,
                0,
                0,
                0,
                0).toDate();

    } catch (final IllegalArgumentException e) {
        // Log failure
    }
    return result;
}

'几乎'是因为我收到0x0126810d和EET(UTC + 2 / DST时为+3)时区,我收到:

java.lang.IllegalArgumentException:由于时区而导致的非法瞬间偏移过渡:1930-06-20T22:00:00.000

至少使用JODA 1.6。我不能轻易切换。但是我希望它是1930-06-21T00:00:00.000+02:00,而且我不关心UTC表示形式。

  1. 是否有可能(java.util.date可以存储这样的日期吗?
  2. 确定,实现这一目标的任何更好的高性能方法(JODA只是这里的补救措施,并不重要)?

是,我知道这次不存在:

roman@node4:$ zdump -v Europe/Kiev | grep 1930
Europe/Kiev  Fri Jun 20 21:59:59 1930 UTC = Fri Jun 20 23:59:59 1930 EET isdst=0 gmtoff=7200
Europe/Kiev  Fri Jun 20 22:00:00 1930 UTC = Sat Jun 21 01:00:00 1930 MSK isdst=0 gmtoff=10800
java date jodatime date-conversion
4个回答
1
投票

我建议以下内容:

Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month);
cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
result = cal.getTime();

1
投票

确定,我认为我可以通过以下方法来复制您的问题:

    TimeZone.setDefault(TimeZone.getTimeZone("Europe/Kiev"));
    System.out.println( extract(0x0126810d));

((以前我用“ EET”尝试过,但显然总共得到了不同的时区)

我收到一个非法的参数异常,尽管它提到的日期有些不同。这可能是由于我的Joda版本。

由于时区偏移量转换而导致的非法时刻(夏令时“ gap”:1930-06-21T00:00:00.000(欧洲/基辅)

嗯,解决这个问题的方法不在欧洲/基辅地区,至少是为了乔达的转换:

public static Date extract(final int intDate) {
    Date result = null;
    DateTimeZone tz = DateTimeZone.forOffsetHours(2);

    try {
        result = new DateTime(
                intDate / 10000,
                (intDate / 100) % 100,
                intDate % 100,
                0,
                0,
                0,
                0,
                tz).toDate();

    } catch (final IllegalArgumentException e) {
        System.err.println(e.getMessage());
        return null;
    }
    return result;
}

这将避免该错误。如果希望提高性能,以防多次调用tz方法,则可以将extract变量定义和初始化移至某个字段。

请注意,当您使用默认日期格式打印结果的Date对象时,该日期格式又使用默认时区(欧洲/基辅),结果将是:

[Eat 1930年6月21日星期六01:00:00

您可以使用以下命令正确打印它:

SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
fmt.setTimeZone(TimeZone.getTimeZone("GMT+2"));


System.out.println(fmt.format( extract(0x0126810d)));

但是如果您不想考虑夏令时,则应该像对待UTC一样对待日期。确实,这取决于您要如何处理它们。

最后一点:用Calendar达到相同的结果确实很容易:

public static Date extract2(final int intDate) {
    cal.set(intDate / 10000, ( intDate / 100 ) % 100 - 1, intDate % 100);
    return cal.getTime();
}

cal是在字段中设置的Calendar实例,以避免重复创建和清除它:

public static final Calendar cal;
static {
    cal = Calendar.getInstance();
    cal.clear();
}

(不过要注意多线程)。

不确定您提到的性能问题以及差异有多关键。


0
投票

好,最后得到以下片段,它的工作与我的期望最接近。像SDF一样,但速度要快很多倍-就像没有字符串解析一样只是为了获取数字:

import org.joda.time.DateTime;
import org.joda.time.LocalDate;

public static Date toDateJoda(int intDate) {
    LocalDate ldt = new LocalDate(
        intDate / 10000,
        (intDate / 100) % 100,
        intDate % 100);

    DateTime dt = ldt.toDateTimeAtStartOfDay();
    return dt.toDate();
}

解析所有内容,并为我的情况获取下一个有效日期/时间。


0
投票

java.time和LocalDate

© www.soinside.com 2019 - 2024. All rights reserved.