Skip to content

Instantly share code, notes, and snippets.

@Ingwersaft
Created March 4, 2019 10:41
Show Gist options
  • Select an option

  • Save Ingwersaft/6970068ba352cc23112401ae0a11fe8d to your computer and use it in GitHub Desktop.

Select an option

Save Ingwersaft/6970068ba352cc23112401ae0a11fe8d to your computer and use it in GitHub Desktop.
Timecamp API: Calculate daily time in industrial hours (minutes are 1/100, not 1/60) - Klaxon as deserialization lib
package com.mkring
import com.beust.klaxon.Converter
import com.beust.klaxon.Json
import com.beust.klaxon.JsonValue
import com.beust.klaxon.Klaxon
import java.net.URL
import java.text.DecimalFormat
import java.time.Month
import java.time.YearMonth
val token = "<token>"
fun main(args: Array<String>) {
val yearMonth = YearMonth.of(2019, Month.FEBRUARY)
val firstOfMonth = yearMonth.atDay(1)
val last = yearMonth.atEndOfMonth()
println("requesting from $firstOfMonth till $last")
val data =
URL("https://www.timecamp.com/third_party/api/entries/format/json/api_token/$token/from/$firstOfMonth/to/$last/").readText()
println(data)
val entries = Entries.fromJson(data)
val daysToMinutes = entries
.filter { it.name == "<projectfilter>" }
.groupBy { it.date }
.map {
it.key to
it.value
.map { it.duration }
.map { it.toInt() }.sum()
}.toSet()
daysToMinutes
.forEach {
val industrialHours = toIndustrialHours(it.second)
println("${it.first}\t${industrialHours.roundTo2Decimals()}")
}
val total = toIndustrialHours(daysToMinutes.map { it.second }.sum())
println("\ntotal for month: ${total.roundTo2Decimals()}")
}
private fun toIndustrialHours(given: Int): Double {
val totalMin = given / 60
val hours = totalMin / 60
val min = totalMin % 60
return hours.toDouble() + (min.toDouble() / 60.0)
}
fun Double.roundTo2Decimals(): Double {
val df2 = DecimalFormat("###.##")
return java.lang.Double.valueOf(df2.format(this))
}
private fun <T> Klaxon.convert(
k: kotlin.reflect.KClass<*>,
fromJson: (JsonValue) -> T,
toJson: (T) -> String,
isUnion: Boolean = false
) =
this.converter(object : Converter {
@Suppress("UNCHECKED_CAST")
override fun toJson(value: Any) = toJson(value as T)
override fun fromJson(jv: JsonValue) = fromJson(jv) as Any
override fun canConvert(cls: Class<*>) = cls == k.java || (isUnion && cls.superclass == k.java)
})
private val klaxon = Klaxon()
class Entries(elements: Collection<Entry>) : ArrayList<Entry>(elements) {
public fun toJson() = klaxon.toJsonString(this)
companion object {
public fun fromJson(json: String) = Entries(klaxon.parseArray<Entry>(json)!!)
}
}
data class Entry(
val id: String,
val duration: String,
@Json(name = "user_id")
val userID: String,
@Json(name = "user_name")
val userName: String,
@Json(name = "task_id")
val taskID: String,
@Json(name = "last_modify")
val lastModify: String,
val date: String,
@Json(name = "start_time")
val startTime: String,
@Json(name = "end_time")
val endTime: String,
val locked: String,
val name: String,
@Json(name = "addons_external_id")
val addonsExternalID: String,
val billable: Long,
@Json(name = "invoiceId")
val invoiceID: String,
val color: String,
val description: String
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment