javaandroiddatecalendarcontainskey

Why is Calendar value different?


I have to count the number of times depending on year, month, day, hour, minute.(second is unified to zero, I don't need second)

I chose HashMap as the data structure.

HashMap<Calendar,Integer> arr_time; 

If there are same time(year,month,day,hour,minute) already, I want to increase the Integer, or add a new time(year,month,day,hour,minute).

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);
}

I thought it would recognize the same calendar if year, month, day, hour, and minute were the same. But it was not.

What is the problem?

I didn't use "Date". It's because, Android Devloper said like this.

Date(int year, int month, int date, int hrs, int min, int sec) This constructor was deprecated in API level 1. As of JDK version 1.1, replaced by Calendar.set(year + 1900, month, date, hrs, min, sec) or GregorianCalendar(year + 1900, month, date, hrs, min, sec).


Solution

  • Never use Calendar

    The terrible Calendar class was supplanted by the java.time classes years ago, specifically ZonedDateTime.

    Time zone

    You are ignoring the crucial issue of time zone. A date and time-of-day have no real meaning until you provide the context of time zone (or offset-from-UTC). For example, noon is Europe/Paris is much later than noon in Asia/Tokyo and much earlier than noon in America/Montreal.

    ZonedDateTime

    Represent a date and time-of-day with time zone with the ZonedDateTime class.

    ZoneID

    Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

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

    truncatedTo

    If you want to set the second and fractional second both to zero, truncate to the minute.

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

    LocalDateTime

    If, for your counting purposes, you want to consider only the date with time-of-day while ignoring the time zone, extract a LocalDateTime. A LocalDateTime is simply a date with time-of-day, and lacks any concept of time zone or offset-from-UTC.

    LocalDateTime ldt = zdt.toLocalDateTime() ;
    

    MapSortedMapTreeMap

    With a LocalDateTime in hand, you can do your counting. Make a Map where the key is a LocalDateTime, and the value is an Integer.

    I imagine you will care about the sorted order of the date-time keys, so use a SortedMap. A TreeMap is one such implementation.

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

    For each LocalDateTime, retrieve an Integer object from the Map. Increment the number count, and replace the old Integer object with a new one.

    Using a Map has been covered many hundreds, if not thousands, of times already on Stack Overflow. So search if you need more discussion and examples of that.


    About java.time

    The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

    To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

    The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

    You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

    Where to obtain the java.time classes?