【问题标题】:Crutch with the Calendar in Java用 Java 编写日历的拐杖
【发布时间】:2021-07-09 22:48:45
【问题描述】:

我正在为 android 编写应用程序。在它开始时,我创建了一个日历,填充诸如 YEAR、MONTH、DAY_OF_MONTH、ERA 和 GMT 时区等容器。

我得到这样的东西 java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=java.util.SimpleTimeZone[id=GMT,offset=0,dstSavings=3600000,useDaylight=false,startYear=0,startMode=0,startMonth=0,startDay=0,startDayOfWeek=0,startTime=0,startTimeMode=0,endMode=0,endMonth=0,endDay=0,endDayOfWeek=0,endTime=0,endTimeMode=0],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2021,MONTH=3,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=14,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]

稍后我需要得到一个像“14-04-2021”这样的字符串,所以我之前使用 getTimeInMillies 为日历创建了一个日期变量。它的所有字段都被零填充。

解析 JSON 后,我需要使用日历键创建地图。看起来像这样。

String key = keys.next();                                                                                                              
Date d = dateFormat.parse(key);                                                                                                        
String rate = String.valueOf(rates.getJsonObject(key).get(get_curr_inf(get_curr_to_r())));                                             
Double rate_ = Double.parseDouble(rate);                                                                                               
Calendar cal = new GregorianCalendar();                                                                                                
cal.setTime(d);                                                                                                                        
Calendar tmp = new GregorianCalendar(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));                 
tmp.setTimeZone(TimeZone.getTimeZone("GMT"));                                                                                          
tmp.set(Calendar.ERA, 1);                                                                                                              
long f = tmp.getTimeInMillis();                                                                                                        
data.put(tmp, rate_);                                                                                                                  

我这样做的方式很奇怪,因为它需要与以前的日历完全相似,因为我使用它来解析地图。

有什么办法让它看起来更好看?

【问题讨论】:

  • 我建议你不要使用DateDateFormatCalendarGregorianCalendar。这些类设计不佳且早已过时,DateFormat 特别是出了名的麻烦。为了让生活更轻松,请改用LocalDateDateTimeFormatter,两者都来自java.time, the modern Java date and time API

标签: java android calendar java.util.calendar


【解决方案1】:

永远不要使用Calendar。那个可怕的类在几年前被现代的 java.time 类所取代。

对于没有时间和时区的仅日期值,请使用LocalDate

在开始时,我创建一个日历,填充 YEAR、MONTH、DAY_OF_MONTH、ERA 和 GMT 时区等容器。

LocalDate ld = LocalDate.of( 2021, Month.APRIL , 14 ) ;

我需要得到一个像“14-04-2021”这样的字符串

DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MM-uuuu" ) ;
String output = ld.format( f ) ;

我需要使用日历键创建地图

Map< LocalDate , … > map = new … ;
map.put( ld , … ) ;

java.time 类内置于 Android 26 及更高版本中。最新的 Android 工具通过API desugaring 为早期的 Android 带来了大部分功能。

【讨论】:

    【解决方案2】:

    java.time

    第一个答案是更改您的地图以使用LocalDate 作为键而不是Calendar。表示同一天的两个LocalDate 对象将始终相等并产生相同的哈希码,因此非常适合用作映射键。按照 Basil Bourque 的回答。

    第二个答案,如果由于某种原因您无法更改映射键的类型,您仍然可以使用现代 Java 日期和时间 API java.time 更好地生成老式的Calendar 对象。

        String key = "14-04-2021";
        LocalDate date = LocalDate.parse(key, DATE_FORMATTER);
        ZonedDateTime zdt = date.atStartOfDay(ZoneOffset.UTC);
        GregorianCalendar tmpCal = GregorianCalendar.from(zdt);
        System.out.println(tmpCal);
    

    我使用了这个格式化程序:

    private static final DateTimeFormatter DATE_FORMATTER
            = DateTimeFormatter.ofPattern("dd-MM-uuuu");
    

    输出是:

    java.util.GregorianCalendar[time=1618358400000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2021,MONTH=3,WEEK_OF_YEAR=15,WEEK_OF_MONTH=3,DAY_OF_MONTH=14,DAY_OF_YEAR=104,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=2,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=0,DST_OFFSET=0]

    它不完全等于你得到的结果,所以不会与你旧方法产生的Calendar 对象兼容。一个区别是所有字段都已设置。 java.time 不能产生一个 Calendar 只像以前那样设置选定的字段。可以消除另一个差异:我的时区是 UTC 而不是 GMT。在实践中它们是相同的。要获取 GMT,请使用 ZoneId.of("GMT") 而不是 ZoneOffset.UTC

    因此,如果您可以强制现在所有映射键都以新方式生成,我应该说您已经设置好了。

    问题:java.time 不需要 Android API 26 级吗?

    java.time 在较旧和较新的 Android 设备上都能很好地工作。它只需要至少 Java 6

    • 在 Java 8 及更高版本以及更新的 Android 设备(从 API 级别 26 起)中,现代 API 是内置的。
    • 在非 Android 的 Java 6 和 7 中,获取 ThreeTen Backport,这是现代类的后向端口(对于 JSR 310,ThreeTen;请参阅底部的链接)。
    • 在较旧的 Android 上,请使用脱糖或 Android 版本的 ThreeTen Backport。它被称为 ThreeTenABP。在后一种情况下,请确保从 org.threeten.bp 导入日期和时间类以及子包。

    链接

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-07
      • 2010-09-05
      • 1970-01-01
      • 2022-10-18
      • 2011-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多