日历值为何不同?

时间:2019-02-20 06:17:59

标签: java android date calendar containskey

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

我选择HashMap作为数据结构。

HashMap<Calendar,Integer> arr_time; 

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

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年,int月,int日期,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,秒)。

2 个答案:

答案 0 :(得分:1)

请勿使用Calendar

可怕的Calendar类在几年前被 java.time 类取代,特别是ZonedDateTime

时区

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

ZonedDateTime

使用ZonedDateTime类表示带有时区的日期和时间。

ZoneID

Continent/Region的格式指定proper time zone name,例如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

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

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

对于每个LocalDateTime,从Integer中检索Map对象。递增计数,然后用新的Integer对象替换。

使用Map已经在Stack Overflow上进行了数百次(甚至数千次)的讨论。因此,搜索是否需要更多讨论和示例。


关于 java.time

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

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

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

在哪里获取java.time类?

答案 1 :(得分:0)

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的形式结束并被计算在内。

要根据LocalDateTime个变量创建一个int

    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-arg set方法的行为使很多人感到惊讶,并且在该类设计不良的许多点中只是次要点。您不应该使用它。自2014年以来,我们有了java.time,因此实际上没有理由。

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

是的,java.time在较新和较旧的Android设备上均可正常运行。它只需要至少 Java 6

  • 在Java 8和更高版本以及更新的Android设备(API级别26以上)中,内置了现代API。
  • 在Java 6和7中,获得了ThreeTen反向端口,这是现代类的反向端口(JSR 310的ThreeTen;请参见底部的链接)。
  • 在(较旧的)Android上,使用Android版本的ThreeTen Backport。叫做ThreeTenABP。并确保您使用子包从org.threeten.bp导入日期和时间类。

链接