Search code examples
javadatekotlinjava.util.calendar

GregorianCalendar gives wrong day number


I've the below code, where I'm trying to post a sales order transaction, with date and qty, once I', getting the day of the transaction date, it is lagging 31 days, and apparently the Dec 1st is considered to be day number 1 in he year!! Anything wrong in my code, or how can I fix it?!

import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util.*

data class transaction (var date: LocalDate, var quantity: Double) {

    private var calendar: Calendar = 
            GregorianCalendar(date.year, date.monthValue, date.dayOfMonth)
    var day: Int
        get() = calendar.get(Calendar.DAY_OF_YEAR)
        set(value) = TODO()
}

val formatter: DateTimeFormatter
    get() = DateTimeFormatter.ofPattern("dd.MM.yyyy", Locale.ENGLISH)

fun main(args: Array<String>) {
    var salesOrders = ArrayList<transaction>()
    salesOrders.add(transaction(LocalDate.parse("01.01.2018", formatter), 5.0))

    println(salesOrders[0].date.dayOfMonth) // prints: 1
    println(salesOrders[0].date.monthValue) // prints: 1
    println(salesOrders[0].date.year)       // prints: 2018
    println(salesOrders[0].day)             // prints 32 ??!!
}

Solution

  • I recommend you drop the use of Calendar and GregorianCalendar completely.

        println(salesOrders[0].date.dayOfYear)  // prints 1
    

    I haven’t got Kotlin, so I have not tested. Should there be a typo you cannot solve, please follow up in a comment.

    Calendar and GregorianCalendar are long outdated, and the modern Java date and time API to which LocalDate belongs is so much nicer to work with. And offers all the functionality you could wish for.

    I understood form your comment that you need a unique identifier for each day over the years. You have been using calendar.timeInMillis. First, that is a poor identifier because it varies with time zone. Instead I suggest using the LocalDate itself or its string representation that you get from date.toString. If you need a numeric identifier (like you had from calendar.timeInMillis), you may use date.toEpochDay. This is a count of days since the epoch of January 1, 1970, so is unique for each day (and unaffected by time zone).