我必须根据年,月,日,小时,分钟来计算次数。秒统一为零,我不需要秒)
我选择了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/Paris
比Asia/Tokyo
中午晚得多,在America/Montreal
中比中午早得多。
ZonedDateTime
用ZonedDateTime
类表示具有时区的日期和时间。
ZoneID
以Continent/Region
的格式指定正确的时区名称,例如America/Montreal
、Africa/Casablanca
或Pacific/Auckland
。切勿使用 2-4 个字母的缩写,例如EST
或IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
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
如果出于计数目的,您只想考虑日期和一天中的时间,而忽略时区,请提取LocalDateTime
。LocalDateTime
只是一个带有时间的日期,没有任何时区或 UTC 偏移量的概念。
LocalDateTime ldt = zdt.toLocalDateTime() ;
Map
➙SortedMap
➙TreeMap
有了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.Date
、Calendar
和SimpleDateFormat
。
要了解更多信息,请参阅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
由于您将mMonth
与Calendar
一起使用,我假设它是从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,并进行了非常详尽的解释。