用Java破解日历



我正在为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为之前的日历创建了一个Date变量。它的所有字段都用零填充。

解析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_);                                                                                                                  

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

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

切勿使用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及更高版本中。最新的安卓工具通过API降级的方式将大部分功能引入早期的安卓。

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不需要安卓API 26级吗

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

  • 在Java 8及更高版本中,以及在较新的Android设备上(从API 26级开始(,现代API内置
  • 在非Android Java 6和7中,获得ThreeTen Backport,即现代类的Backport(JSR310的ThreeTen;请参阅底部的链接(
  • 在旧的安卓系统上,可以使用desugaring或安卓版的ThreeTen Backport。它被称为ThreeTenABP。在后一种情况下,请确保使用子包从org.threeten.bp导入日期和时间类

链接

  • Oracle教程:日期时间,解释如何使用java.Time
  • Java规范请求(JSR(310,其中首次描述了java.time
  • ThreeTen Backport项目,java.time到Java 6和7的Backport(JSR-310的ThreeTen(
  • 通过降级提供Java 8+API
  • ThreeTenABP,安卓版ThreeTen背包
  • 问题:如何在Android项目中使用ThreeTenABP,有一个非常彻底的解释

最新更新