Created
March 4, 2019 10:41
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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