Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将整数YYYYMMDD转换为具有本地时区的java.util.Date的好方法_Java_Date_Jodatime_Date Conversion - Fatal编程技术网

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

将整数YYYYMMDD转换为具有本地时区的java.util.Date的好方法,java,date,jodatime,date-conversion,Java,Date,Jodatime,Date Conversion,我知道这个问题可能看起来像常见问题,但关键是时区和性能。我有整数YYYYMMDD日期(例如20150131)。这是一个很好的“几乎可以工作”的解决方案: import org.joda.time.DateTime; import java.util.Date; // ... public Date extract(final int intDate) { Date result = null; try { result = new DateTime(

我知道这个问题可能看起来像常见问题,但关键是时区和性能。我有整数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(DST时UTC+2/+3)时区:

java.lang.IllegalArgumentException:由于时区的原因而导致的非法即时 偏移转换:1930-06-20T22:00:00.000

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

  • 是否可能(可以
    java.util.date
    存储这样的日期)
  • 好的,有没有更好的高性能方法来实现这一点(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
    

    我建议如下:

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

    好的,我想我成功地复制了你的问题,方法是:

        TimeZone.setDefault(TimeZone.getTimeZone("Europe/Kiev"));
        System.out.println( extract(0x0126810d));
    
    (之前我用“EET”试过,但显然那是一个完全不同的时区)

    我得到一个非法参数例外,尽管它提到的日期有点不同。这可能是因为我对乔达的看法

    Illegal instant due to time zone offset transition (daylight savings time 'gap'): 1930-06-21T00:00:00.000 (Europe/Kiev) 这样可以避免错误。如果希望在多次调用
    extract
    方法时提高性能,可以将
    tz
    变量定义和初始化移动到字段中

    请注意,当您使用默认日期格式打印生成的
    Date
    对象时,结果将是:

    Sat Jun 21 01:00:00 EET 1930 但是,如果您不想考虑DST,您应该将日期当作UTC来处理。这取决于你想用它们做什么,真的

    最后一点注意:使用
    日历
    ,很容易达到同样的效果:

    public static Date extract2(final int intDate) {
        cal.set(intDate / 10000, ( intDate / 100 ) % 100 - 1, intDate % 100);
        return cal.getTime();
    }
    
    其中
    cal
    是在字段中设置的
    日历
    实例,以避免重复创建和清除它:

    public static final Calendar cal;
    static {
        cal = Calendar.getInstance();
        cal.clear();
    }
    
    (不过要注意多线程)


    我不确定您提到的性能问题,以及差异有多大。

    好的,最后得到了以下片段,它的效果最接近我的预期。与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();
    }
    
    解析所有内容并获取下一个有效的日期/时间(如我的情况)。

    java.time和LocalDate 无论使用Joda Time(如您的问题中所述)还是java.Time(现代java日期和时间API),我相信您的问题的解决方案都是使用
    LocalDate
    。我建议您坚持这一点,不要使用
    org.joda.time.DateTime
    java.util.Date
    。尤其不是后者,它的设计总是很糟糕,现在已经过时很久了

    我正在向你展示自己的方式

        int intDate = 19300621; // 0x0126810d
    
        String asString = String.valueOf(intDate);
        LocalDate date = LocalDate.parse(asString, DateTimeFormatter.BASIC_ISO_DATE);
    
        System.out.println(date);
    
    1930-06-21

    我发现这段代码比进行除法和模运算的代码更容易阅读。虽然效率不高,但对于20个案例中的19个以上来说,这应该不值得担心。如果您喜欢划分,当然也可以使用java.time进行划分:

        int year = intDate / 10000;
        int monthDay = intDate % 10000;
        int month = monthDay / 100;
        int day = monthDay % 100;
        LocalDate date = LocalDate.of(year, month, day);
    
    如果您确实需要一个java.util.Date,用于尚未升级到java的遗留API。时间(或Joda时间),按如下方式转换(无论您使用上述哪种转换):

    当我的默认时区设置为Europe/Zaporozhye时的输出:

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

    (我们注意到,由于过渡到夏季时间(DST),我们得到了01:00:00。00:00:00的时间在该时区的这一天不存在。)

    如果仍然使用Joda时间 如果您仍在使用Joda Time,那么您自己使用
    ToDateTimeAtStarToDay()
    的答案就可以了

    PS我重现了你关于Joda Time 2.9.9的问题,我的时区设置为Europe/Zaporozhye,你的整数是19300621(不知道你为什么把它设为十六进制,0x0126810d)。我得到了一个与您类似的异常:
    org.joda.time.IllegalInstantException:由于时区偏移转换(夏令时“间隙”)而导致的非法瞬间:1930-06-21T00:00:00.000(欧洲/扎波罗齐)

    链接
    解释如何使用java.time。

    我复制了您的函数(使其成为静态函数)。我使用了
    TimeZone.setDefault(TimeZone.getTimeZone(“EET”)后接
    System.out.println(提取(0x0126810d))。我没有任何例外。您使用的是什么版本的Java和Joda?1.6,我至少在不久的将来无法更改。您使用Joda而不是
    Calendar
    这样做的任何特殊原因对我也适用-使用Joda 2.7输出1930年6月21日星期六00:00:00 EET。在你编辑完Joda 1.6后,我下载并试用了它。仍然没有例外-它输出“1930年6月21日星期六00:15:36 EET”。我不知道额外的时间是从哪里来的。。。我想知道这是否与系统设置有关。我使用的是Windows8、Java7和Joda——上面引用的两个版本。我确实发现了这篇文章——对2.1版之前的Joda版本在时区上的性能提出了质疑——也许时区文件中存在差异。你的系统是Linux吗?你能运行zdump-v Europe/Kiev | grep 1930吗?
    ?顺便说一句,GregorianCalendar可以提供更好的帮助,但它有“当前”时刻初始化,并尝试让他获得-1、-1、-1之类的东西。
        int intDate = 19300621; // 0x0126810d
    
        String asString = String.valueOf(intDate);
        LocalDate date = LocalDate.parse(asString, DateTimeFormatter.BASIC_ISO_DATE);
    
        System.out.println(date);
    
        int year = intDate / 10000;
        int monthDay = intDate % 10000;
        int month = monthDay / 100;
        int day = monthDay % 100;
        LocalDate date = LocalDate.of(year, month, day);
    
        Instant asInstant = date.atStartOfDay(ZoneId.systemDefault()).toInstant();
        Date oldfashionedDate = Date.from(asInstant);
        System.out.println(oldfashionedDate);