为什么日历值不同



我必须根据年,月,日,小时,分钟来计算次数。秒统一为零,我不需要秒)

我选择了HashMap作为数据结构。

HashMap<Calendar,Integer> arr_time; 

如果已经有相同的时间(年,月,日,小时,分钟),我想增加整数,或添加新时间(年,月,日,小时,分钟)。

Calendar calendar = Calendar.getInstance();
calendar.set(mYear,mMonth,mDay,mHour,mMinute,0);
if(arr_time.containsKey(calendar)){
// increase Integer value
// ++1;
}else{
// add new time 
// arr_time.put(calendar,1);
}

我认为如果年、月、日、小时和分钟相同,它会识别相同的日历。 但事实并非如此。

问题出在哪里?

我没有使用"日期"。 这是因为,Android Devloper是这样说的。

日期(int year, int month, int date, int hrs, int min, int sec) 此构造函数在 API 级别 1 中已弃用。从JDK版本1.1开始,由Calendar.set(year + 1900,month,date,hrs,min,sec)或GregorianCalendar(year + 1900,month,date,hrs,min,sec)取代。

永远不要使用Calendar

糟糕的Calendar类在几年前被java.time类所取代,特别是ZonedDateTime

时区

您忽略了时区的关键问题。在提供时区(或 UTC 偏移量)之前,日期和时间没有实际意义。 例如,中午是Europe/ParisAsia/Tokyo中午晚得多,在America/Montreal中比中午早得多。

ZonedDateTime

ZonedDateTime类表示具有时区的日期和时间。

ZoneID

Continent/Region的格式指定正确的时区名称,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 2-4 个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;

truncatedTo

如果要将秒和小数秒都设置为零,请截断为分钟。

ZonedDateTime zdt = ZonedDateTime.now( z ).truncatedTo( ChronoUnit.MINUTES ) ;  // Set the whole second and the fractional second both to zero.

LocalDateTime

如果出于计数目的,您只想考虑日期和一天中的时间,而忽略时区,请提取LocalDateTimeLocalDateTime只是一个带有时间的日期,没有任何时区或 UTC 偏移量的概念。

LocalDateTime ldt = zdt.toLocalDateTime() ;

MapSortedMapTreeMap

有了LocalDateTime,您就可以进行计数。创建一个Map,其中键是LocalDateTime,值是Integer

我想你会关心日期时间键的排序顺序,所以使用SortedMap.TreeMap就是这样一种实现。

SortedMap< LocalDateTime , Integer > map = new TreeMap() ;

对于每个LocalDateTime,从Map中检索一个Integer对象。递增数字计数,并将旧的Integer对象替换为新对象。

使用Map已经在Stack Overflow上覆盖了数百次,如果不是数千次的话。因此,如果您需要更多讨论和示例,请搜索。


关于java.time

java.time框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧传统日期时间类,如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参阅Oracle 教程。并搜索堆栈溢出以获取许多示例和解释。规范为 JSR 310。

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

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

从哪里获得java.time类?

Java SE 8、Java SE 9、Java SE
  • 10、Java SE 11及更高版本 - 标准 Java API 的一部分,具有捆绑实现。
    • Java 9添加了一些小功能和修复。
  • Java SE 6 和 Java
  • SE7
    • 大多数java.time功能在ThreeTen-Backport中向后移植到 Java 6 和 7。
  • Android
    • 更高版本的java.time类的 Android 捆绑实现。
    • 对于早期的Android(<26),ThreeTenABP项目适应了ThreeTen-Backport(如上所述)。请参阅如何使用ThreeTenABP...

java.time

Map<LocalDateTime, Integer> arr_time = new HashMap<>();
ZoneId zone = ZoneId.of("Antarctica/Vostok");
for (int i = 0; i < 10; i++) {
LocalDateTime now = LocalDateTime.now(zone).truncatedTo(ChronoUnit.MINUTES);
arr_time.compute(now, (ldt, oldCount) -> oldCount == null ? Integer.valueOf(1) : oldCount + 1);
TimeUnit.MILLISECONDS.sleep(103);
}
System.out.println(arr_time);

当我刚才运行代码时,我得到:

{2019-02-20T13:42=10}

我录制了10次,中间睡觉以确保它们不完全相同。但是因为我把每个都截断到整分钟,所以它们最终都被2019-02-20T13:42并一起计算。

要从int变量创建LocalDateTime,请执行以下操作:

int mYear = 2019;
int mMonth = Calendar.JANUARY;
int mDay = 31;
int mHour = 23;
int mMinute = 45;
LocalDateTime ldt = LocalDateTime.of(mYear, mMonth + 1, mDay, mHour, mMinute);
System.out.println(ldt);

2019-01-31T23:45

由于您将mMonthCalendar一起使用,我假设它是从0开始的。LocalDateTime数字从 1 开始几个月,就像人类一样,所以我需要加 1。

您的代码中出了什么问题?

calendar.set(mYear,mMonth,mDay,mHour,mMinute,0)设置年、月、日、小时、分钟和秒,但不设置毫秒。由于每个Calendar对象都是使用当前时间创建的,因此毫秒通常会有所不同,因此即使您设置了相同的值,Calendar对象仍然不相等。

6-argset方法的这种行为让许多人感到惊讶,这只是类设计不佳的许多点中的一个小点。你不应该使用它。我们从2014年开始就有java.time,所以真的没有理由。

问:我可以在 Android 上使用 java.time 吗?

是的,java.time在较旧和较新的Android设备上运行良好。它只需要至少Java6

  • 在 Java 8 及更高版本以及较新的 Android 设备(从 API 级别 26)中,内置了现代 API。
  • 在Java 6和7中获取ThreeTen Backport,现代类的反向移植(JSR 310的ThreeTen;请参阅底部的链接)。
  • 在(较旧的)Android上使用Android版本的ThreeTen Backport。它被称为ThreeTenABP。并确保从带有子包的org.threeten.bp导入日期和时间类。

链接

  • Oracle 教程:日期时间解释如何使用 java.time。
  • Java 规范请求 (JSR) 310,其中首次描述了java.time
  • ThreeTen Backport 项目,将java.time向 Java 6 和 7 的反向移植(ThreeTen 用于 JSR-310)。
  • ThreeTenABP,ThreeTen Backport 的安卓版
  • 问:如何在Android项目中使用ThreeTenABP,并进行了非常详尽的解释。

相关内容

  • 没有找到相关文章

最新更新