简体   繁体   中英

Fast way to get month number from java.util.Date

I have a recyclerview in my Android app with many dates. In order to sort data & insert separators between items grouped by month+year, i use following funs:

private fun monthFromDate(date: Date): Int {
    val calendar = Calendar.getInstance()
    calendar.time = date
    return calendar.get(Calendar.MONTH)
}

private fun yearFromDate(date: Date): Int {
    val calendar = Calendar.getInstance()
    calendar.time = date
    return calendar.get(Calendar.YEAR)
}

I think its bad idea always call Calendar.getInstance(). I don't want to introduce a local variable either. (btw all methods like date.month date.year are deprecated )

The question: I have two util.java.Date instances. Let them be equal if both month & year are equal. How can I implement this fun in fast & optimal way?

Date.getMonth() although deprecated is fine. Java keeps backward compatability.

If using Java 8, you can do some benchmark of your version Calendar.getInstance().get(Calendar.MONTH) vs the new LocalDate.ofEpochDay(new Date().getTime()).getMonthValue()

java.time

ShaharT in an answer already mentioned Java 8 as an option. Even on Android Java 7 I believe it's worth considering using JSR-310, the modern Java date and time API also known as java.time for your task. It came out with Java 8, but you can use it too. It is generally much nicer to work with. It includes a class YearMonth for representing a year and a month, just what you need, and this saves you from using two functions and instantiating a Calendar object for each of those two method calls. So I wanted to show you the correct way to make that conversion.

I am sorry that I cannot write Kotlin code. You will have to make do with Java code, and I trust you to adapt. The Java code is:

private ZoneId zone = ZoneId.of("Europe/Moscow");

private YearMonth yearMonthFromDate(Date date) {
    ZonedDateTime dateTime = date.toInstant().atZone(zone);
    return YearMonth.from(dateTime);
}

Please insert your desired time zone if you didn't want Europe/Moscow.

Now you are at it, if you go down this avenue, you may also want to consider whether you want Date objects in you app at all, or you prefer classes from JSR-310. The Date and Calendar classes are considered long outmoded.

Performance

On my Mac I ran 100 000 Date objects through the above method in 37 milliseconds. It may not be the same on an average Android device, but I'm not convinced that you need to worry about how fast the conversion is. General rule of thumb is you shouldn't worry about it until you see a problem in a realistic setting. If not sure, then test in a realistic setting at your earliest convenience.

To use on Android

To use JSR-310 on Android you will need to have the ThreeTenABP (ABP for Android backport). It is all very well and thoroughly explained in this question: How to use ThreeTenABP in Android Project .

It is not very clear, why is Calendar.getInstance() is sub optimal. However, for your requirement, how about coding it like this:

private fun getYearMonth(date: Date): Int {
    val calendar = Calendar.getInstance()
    calendar.time = date
    return calendar.get(Calendar.YEAR) * 100 + calendar.get(Calendar.MONTH) 
}

Gives you access to yearMonth in single interger, like 201711

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM